diff --git a/api/data/info.go b/api/data/info.go index cd330f0..5ccbe21 100644 --- a/api/data/info.go +++ b/api/data/info.go @@ -17,11 +17,12 @@ const ( type ( // BucketInfo stores basic bucket data. BucketInfo struct { - Name string - CID *cid.ID - Owner *owner.ID - Created time.Time - BasicACL uint32 + Name string + CID *cid.ID + Owner *owner.ID + Created time.Time + BasicACL uint32 + LocationConstraint string } // ObjectInfo holds S3 object data. diff --git a/api/handler/info.go b/api/handler/info.go index 0becc38..f143095 100644 --- a/api/handler/info.go +++ b/api/handler/info.go @@ -9,12 +9,18 @@ import ( func (h *handler) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) { reqInfo := api.GetReqInfo(r.Context()) - if _, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName); err != nil { - h.logAndSendError(w, "something went wrong", reqInfo, err) + bktInfo, err := h.obj.GetBucketInfo(r.Context(), reqInfo.BucketName) + if err != nil { + h.logAndSendError(w, "could not get bucket info", reqInfo, err) return } - if err := api.EncodeToResponse(w, LocationResponse{Location: ""}); err != nil { - h.logAndSendError(w, "something went wrong", reqInfo, err) + if err = checkOwner(bktInfo, r.Header.Get(api.AmzExpectedBucketOwner)); err != nil { + h.logAndSendError(w, "expected owner doesn't match", reqInfo, err) + return + } + + if err = api.EncodeToResponse(w, LocationResponse{Location: bktInfo.LocationConstraint}); err != nil { + h.logAndSendError(w, "couldn't encode bucket location response", reqInfo, err) } } diff --git a/api/handler/put.go b/api/handler/put.go index 3aa4166..38574d2 100644 --- a/api/handler/put.go +++ b/api/handler/put.go @@ -549,6 +549,7 @@ func (h *handler) CreateBucketHandler(w http.ResponseWriter, r *http.Request) { for _, placementPolicy := range policies { if placementPolicy.LocationConstraint == createParams.LocationConstraint { p.Policy = placementPolicy.Policy + p.LocationConstraint = createParams.LocationConstraint break } } diff --git a/api/layer/container.go b/api/layer/container.go index 8b81616..a807f1a 100644 --- a/api/layer/container.go +++ b/api/layer/container.go @@ -26,6 +26,8 @@ type ( } ) +const locationConstraintAttr = ".s3-location-constraint" + func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInfo, error) { var ( err error @@ -70,6 +72,8 @@ func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*data.BucketInf } info.Created = time.Unix(unix, 0) + case locationConstraintAttr: + info.LocationConstraint = val } } @@ -117,16 +121,25 @@ func (n *layer) containerList(ctx context.Context) ([]*data.BucketInfo, error) { func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) { var err error bktInfo := &data.BucketInfo{ - Name: p.Name, - Owner: n.Owner(ctx), - Created: time.Now(), - BasicACL: p.ACL, + Name: p.Name, + Owner: n.Owner(ctx), + Created: time.Now(), + BasicACL: p.ACL, + LocationConstraint: p.LocationConstraint, } - cnr := container.New( + + options := []container.Option{ container.WithPolicy(p.Policy), container.WithCustomBasicACL(p.ACL), container.WithAttribute(container.AttributeName, p.Name), - container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(bktInfo.Created.Unix(), 10))) + container.WithAttribute(container.AttributeTimestamp, strconv.FormatInt(bktInfo.Created.Unix(), 10)), + } + + if p.LocationConstraint != "" { + options = append(options, container.WithAttribute(locationConstraintAttr, p.LocationConstraint)) + } + + cnr := container.New(options...) container.SetNativeName(cnr, p.Name) cnr.SetSessionToken(p.SessionToken) diff --git a/api/layer/layer.go b/api/layer/layer.go index 056ceb9..f5e382e 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -131,11 +131,12 @@ type ( } // CreateBucketParams stores bucket create request parameters. CreateBucketParams struct { - Name string - ACL uint32 - Policy *netmap.PlacementPolicy - EACL *eacl.Table - SessionToken *session.Token + Name string + ACL uint32 + Policy *netmap.PlacementPolicy + EACL *eacl.Table + SessionToken *session.Token + LocationConstraint string } // PutBucketACLParams stores put bucket acl request parameters. PutBucketACLParams struct { diff --git a/docs/aws_s3_compat.md b/docs/aws_s3_compat.md index b62feef..ce2340b 100644 --- a/docs/aws_s3_compat.md +++ b/docs/aws_s3_compat.md @@ -87,7 +87,7 @@ See also `GetObject` and other method parameters. |----|----------------------|-----------| | 🟢 | CreateBucket | PutBucket | | 🟢 | DeleteBucket | | -| 🔵 | GetBucketLocation | | +| 🟢 | GetBucketLocation | | | 🟢 | HeadBucket | | | 🟢 | ListBuckets | | | 🔵 | PutPublicAccessBlock | |