From 31867b6f759c343dfc94b73b00fd40612300b304 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 28 Jan 2026 13:25:22 -0800 Subject: [PATCH] s3tables: improve account ID handling and define missing error codes Updated getPrincipalFromRequest to prioritize X-Amz-Account-ID header and added getAccountID helper. Defined ErrVersionTokenMismatch and ErrCodeConflict for better optimistic concurrency support. --- weed/s3api/s3tables/handler.go | 40 +++++++++++++++++++++++++++------- weed/s3api/s3tables/types.go | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/weed/s3api/s3tables/handler.go b/weed/s3api/s3tables/handler.go index 59fb2647a..76be2334a 100644 --- a/weed/s3api/s3tables/handler.go +++ b/weed/s3api/s3tables/handler.go @@ -2,6 +2,7 @@ package s3tables import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -23,6 +24,17 @@ const ( ExtendedKeyTags = "s3tables.tags" ) +var ( + ErrVersionTokenMismatch = errors.New("version token mismatch") +) + +type ResourceType string + +const ( + ResourceTypeBucket ResourceType = "bucket" + ResourceTypeTable ResourceType = "table" +) + // S3TablesHandler handles S3 Tables API requests type S3TablesHandler struct { region string @@ -148,20 +160,32 @@ func (h *S3TablesHandler) getPrincipalFromRequest(r *http.Request) string { } // Fallback to request header (e.g., for testing or legacy clients) - principal := r.Header.Get("X-Amz-Principal") - if principal != "" { + if principal := r.Header.Get("X-Amz-Principal"); principal != "" { return principal } - // Default to account ID (owner) + // Fallback to the authenticated account ID + if accountID := r.Header.Get(s3_constants.AmzAccountId); accountID != "" { + return accountID + } + + // Default to handler's default account ID + return h.accountID +} + +// getAccountID returns the authenticated account ID from the request or the handler's default +func (h *S3TablesHandler) getAccountID(r *http.Request) string { + if accountID := r.Header.Get(s3_constants.AmzAccountId); accountID != "" { + return accountID + } return h.accountID } // Request/Response helpers func (h *S3TablesHandler) readRequestBody(r *http.Request, v interface{}) error { - body, err := io.ReadAll(r.Body) defer r.Body.Close() + body, err := io.ReadAll(r.Body) if err != nil { return fmt.Errorf("failed to read request body: %w", err) } @@ -203,10 +227,10 @@ func (h *S3TablesHandler) writeError(w http.ResponseWriter, status int, code, me // ARN generation helpers -func (h *S3TablesHandler) generateTableBucketARN(bucketName string) string { - return fmt.Sprintf("arn:aws:s3tables:%s:%s:bucket/%s", h.region, h.accountID, bucketName) +func (h *S3TablesHandler) generateTableBucketARN(r *http.Request, bucketName string) string { + return fmt.Sprintf("arn:aws:s3tables:%s:%s:bucket/%s", h.region, h.getAccountID(r), bucketName) } -func (h *S3TablesHandler) generateTableARN(bucketName, tableID string) string { - return fmt.Sprintf("arn:aws:s3tables:%s:%s:bucket/%s/table/%s", h.region, h.accountID, bucketName, tableID) +func (h *S3TablesHandler) generateTableARN(r *http.Request, bucketName, tableID string) string { + return fmt.Sprintf("arn:aws:s3tables:%s:%s:bucket/%s/table/%s", h.region, h.getAccountID(r), bucketName, tableID) } diff --git a/weed/s3api/s3tables/types.go b/weed/s3api/s3tables/types.go index 2b7abdba7..f4dc4ef75 100644 --- a/weed/s3api/s3tables/types.go +++ b/weed/s3api/s3tables/types.go @@ -287,4 +287,5 @@ const ( ErrCodeInvalidRequest = "InvalidRequest" ErrCodeInternalError = "InternalError" ErrCodeNoSuchPolicy = "NoSuchPolicy" + ErrCodeConflict = "Conflict" )