forked from TrueCloudLab/frostfs-s3-gw
[#214] Add condition to update eacl
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
a0f59bb348
commit
76fc241bc1
1 changed files with 52 additions and 41 deletions
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/policy"
|
"github.com/nspcc-dev/neofs-node/pkg/policy"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||||
|
@ -30,56 +31,60 @@ type createBucketParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var (
|
var newEaclTable *eacl.Table
|
||||||
err error
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
info *layer.ObjectInfo
|
|
||||||
reqInfo = api.GetReqInfo(r.Context())
|
|
||||||
)
|
|
||||||
|
|
||||||
objectACL, err := parseACLHeaders(r)
|
if containsACLHeaders(r) {
|
||||||
if err != nil {
|
objectACL, err := parseACLHeaders(r)
|
||||||
h.logAndSendError(w, "could not parse object acl", reqInfo, err)
|
if err != nil {
|
||||||
return
|
h.logAndSendError(w, "could not parse object acl", reqInfo, err)
|
||||||
}
|
return
|
||||||
objectACL.Resource = reqInfo.BucketName + "/" + reqInfo.ObjectName
|
}
|
||||||
|
objectACL.Resource = reqInfo.BucketName + "/" + reqInfo.ObjectName
|
||||||
|
|
||||||
bktPolicy, err := aclToPolicy(objectACL)
|
bktPolicy, err := aclToPolicy(objectACL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not translate object acl to bucket policy", reqInfo, err)
|
h.logAndSendError(w, "could not translate object acl to bucket policy", reqInfo, err)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
astChild, err := policyToAst(bktPolicy)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not translate policy to ast", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bacl, err := h.obj.GetBucketACL(r.Context(), reqInfo.BucketName)
|
||||||
|
if err != nil {
|
||||||
|
h.logAndSendError(w, "could not get bucket eacl", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parentAst := tableToAst(bacl.EACL, reqInfo.BucketName)
|
||||||
|
for _, resource := range parentAst.Resources {
|
||||||
|
if resource.Name == bacl.Info.CID.String() {
|
||||||
|
resource.Name = reqInfo.BucketName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if resAst, updated := mergeAst(parentAst, astChild); updated {
|
||||||
|
if newEaclTable, err = astToTable(resAst, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "could not translate ast to table", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
astChild, err := policyToAst(bktPolicy)
|
bktInfo, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName)
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not translate policy to ast", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bacl, err := h.obj.GetBucketACL(r.Context(), reqInfo.BucketName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get bucket eacl", reqInfo, err)
|
h.logAndSendError(w, "could not get bucket eacl", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err = checkOwner(bktInfo, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil {
|
||||||
if err = checkOwner(bacl.Info, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil {
|
|
||||||
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parentAst := tableToAst(bacl.EACL, reqInfo.BucketName)
|
|
||||||
for _, resource := range parentAst.Resources {
|
|
||||||
if resource.Name == bacl.Info.CID.String() {
|
|
||||||
resource.Name = reqInfo.BucketName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resAst, updated := mergeAst(parentAst, astChild)
|
|
||||||
table, err := astToTable(resAst, reqInfo.BucketName)
|
|
||||||
if err != nil {
|
|
||||||
h.logAndSendError(w, "could not translate ast to table", reqInfo, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata := parseMetadata(r)
|
metadata := parseMetadata(r)
|
||||||
if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
if contentType := r.Header.Get(api.ContentType); len(contentType) > 0 {
|
||||||
metadata[api.ContentType] = contentType
|
metadata[api.ContentType] = contentType
|
||||||
|
@ -93,15 +98,16 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Header: metadata,
|
Header: metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
if info, err = h.obj.PutObject(r.Context(), params); err != nil {
|
info, err := h.obj.PutObject(r.Context(), params)
|
||||||
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not upload object", reqInfo, err)
|
h.logAndSendError(w, "could not upload object", reqInfo, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if updated {
|
if newEaclTable != nil {
|
||||||
p := &layer.PutBucketACLParams{
|
p := &layer.PutBucketACLParams{
|
||||||
Name: reqInfo.BucketName,
|
Name: reqInfo.BucketName,
|
||||||
EACL: table,
|
EACL: newEaclTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = h.obj.PutBucketACL(r.Context(), p); err != nil {
|
if err = h.obj.PutBucketACL(r.Context(), p); err != nil {
|
||||||
|
@ -114,6 +120,11 @@ func (h *handler) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
api.WriteSuccessResponseHeadersOnly(w)
|
api.WriteSuccessResponseHeadersOnly(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsACLHeaders(r *http.Request) bool {
|
||||||
|
return r.Header.Get(api.AmzACL) != "" || r.Header.Get(api.AmzGrantRead) != "" ||
|
||||||
|
r.Header.Get(api.AmzGrantFullControl) != "" || r.Header.Get(api.AmzGrantWrite) != ""
|
||||||
|
}
|
||||||
|
|
||||||
func parseMetadata(r *http.Request) map[string]string {
|
func parseMetadata(r *http.Request) map[string]string {
|
||||||
res := make(map[string]string)
|
res := make(map[string]string)
|
||||||
for k, v := range r.Header {
|
for k, v := range r.Header {
|
||||||
|
|
Loading…
Reference in a new issue