Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ release/

# VS Code
.vscode/
/gateway
31 changes: 31 additions & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ type API struct {
config Config
}

// BucketLocationGetter is an interface for getting bucket location.
// This is implemented by the gateway layer to fetch bucket region/location.
type BucketLocationGetter interface {
GetBucketLocation(ctx context.Context, bucketName string) (string, error)
}

// GetBucketInfoWithLocation fetches bucket info along with its location.
func (api *API) GetBucketInfoWithLocation(ctx context.Context, bucketName string) (BucketInfo, error) {
// Get basic bucket info
minioInfo, err := api.objectAPI.GetBucketInfo(ctx, bucketName)
if err != nil {
return BucketInfo{}, err
}

// Try to get location if the objectAPI supports it
location := ""
if locationGetter, ok := api.objectAPI.(BucketLocationGetter); ok {
loc, err := locationGetter.GetBucketLocation(ctx, bucketName)
if err == nil {
location = loc
}
// If error, leave location empty - will default to us-east-1
}

return BucketInfo{
Name: minioInfo.Name,
Created: minioInfo.Created,
Location: location,
}, nil
}

// New constructs a new S3-compatible HTTP API.
func New(objectAPI cmd.ObjectLayer, credsProvider awsig.CredentialsProvider[AuthData], config Config) *API {
v2v4 := awsig.NewV2V4(credsProvider, awsig.V4Config{
Expand Down
11 changes: 10 additions & 1 deletion api/buckethandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,20 @@ func (api *API) HeadBucketHandler(w http.ResponseWriter, r *http.Request) {
return
}

if _, err := api.objectAPI.GetBucketInfo(ctx, bucketName); err != nil {
bucketInfo, err := api.GetBucketInfoWithLocation(ctx, bucketName)
if err != nil {
writeErrorResponseHeadersOnly(w, cmd.ToAPIError(ctx, err))
return
}

// Set the bucket region header
if bucketInfo.Location != "" {
w.Header().Set(xhttp.AmzBucketRegion, bucketInfo.Location)
} else {
// Default to us-east-1 if location is not available
w.Header().Set(xhttp.AmzBucketRegion, "us-east-1")
}

writeSuccessResponseHeadersOnly(w)
}

Expand Down
9 changes: 9 additions & 0 deletions api/datatypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,19 @@ package api

import (
"encoding/xml"
"time"

"storj.io/minio/cmd"
)

// BucketInfo represents bucket metadata.
// This struct extends the MinIO BucketInfo to include location/region information.
type BucketInfo struct {
Name string
Created time.Time
Location string
}

type grantee struct {
XMLNS string `xml:"xmlns:xsi,attr"`
XMLXSI string `xml:"xsi:type,attr"`
Expand Down
27 changes: 24 additions & 3 deletions miniogw/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,17 +335,38 @@ func (layer *gatewayLayer) GetBucketInfo(ctx context.Context, bucketName string)
return minio.BucketInfo{}, err
}

bucket, err := project.StatBucket(ctx, bucketName)
bucketObj, err := project.StatBucket(ctx, bucketName)
if err != nil {
return minio.BucketInfo{}, ConvertError(err, bucketName, "")
}

return minio.BucketInfo{
Name: bucket.Name,
Created: bucket.Created,
Name: bucketObj.Name,
Created: bucketObj.Created,
}, nil
}

// GetBucketLocation returns the location/region of a bucket.
func (layer *gatewayLayer) GetBucketLocation(ctx context.Context, bucketName string) (location string, err error) {
defer mon.Task()(&ctx)(&err)

if err := ValidateBucket(ctx, bucketName); err != nil {
return "", minio.BucketNameInvalid{Bucket: bucketName}
}

project, err := projectFromContext(ctx, bucketName, "")
if err != nil {
return "", err
}

location, err = bucket.GetBucketLocation(ctx, project, bucketName)
if err != nil {
return "", ConvertError(err, bucketName, "")
}

return location, nil
}

func (layer *gatewayLayer) ListBuckets(ctx context.Context) (items []minio.BucketInfo, err error) {
defer mon.Task()(&ctx)(&err)

Expand Down