s3tables: add bucket name validation and fix error handling

- Add isValidBucketName validation function for [a-z0-9_-] characters
- Validate bucket name characters match ARN parsing regex
- Fix error handling in WithFilerClient closure - properly check for lookup errors
- Add error handling for json.Marshal calls (metadata and tags)
- Improve error messages and logging
This commit is contained in:
Chris Lu
2026-01-28 01:12:57 -08:00
parent 22a9fbf062
commit dd7003a328
2 changed files with 35 additions and 4 deletions

View File

@@ -24,12 +24,18 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
return fmt.Errorf("name is required")
}
// Validate bucket name
// Validate bucket name length
if len(req.Name) < 3 || len(req.Name) > 63 {
h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "bucket name must be between 3 and 63 characters")
return fmt.Errorf("invalid bucket name length")
}
// Validate bucket name characters [a-z0-9_-]
if !isValidBucketName(req.Name) {
h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "bucket name must contain only lowercase letters, numbers, hyphens, and underscores")
return fmt.Errorf("invalid bucket name characters")
}
bucketPath := getTableBucketPath(req.Name)
// Check if bucket already exists
@@ -39,12 +45,22 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
Directory: TablesPath,
Name: req.Name,
})
if err == nil && resp.Entry != nil {
if err != nil {
// Not found is expected when creating a new bucket
return nil
}
if resp.Entry != nil {
exists = true
}
return nil
})
if err != nil {
glog.Errorf("S3Tables: failed to check bucket existence: %v", err)
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, "failed to check bucket existence")
return err
}
if exists {
h.writeError(w, http.StatusConflict, ErrCodeBucketAlreadyExists, fmt.Sprintf("table bucket %s already exists", req.Name))
return fmt.Errorf("bucket already exists")
@@ -58,7 +74,12 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
OwnerID: h.accountID,
}
metadataBytes, _ := json.Marshal(metadata)
metadataBytes, err := json.Marshal(metadata)
if err != nil {
glog.Errorf("S3Tables: failed to marshal metadata: %v", err)
h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, "failed to marshal metadata")
return err
}
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
// Create bucket directory
@@ -73,7 +94,10 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
// Set tags if provided
if len(req.Tags) > 0 {
tagsBytes, _ := json.Marshal(req.Tags)
tagsBytes, err := json.Marshal(req.Tags)
if err != nil {
return fmt.Errorf("failed to marshal tags: %w", err)
}
if err := h.setExtendedAttribute(client, bucketPath, ExtendedKeyTags, tagsBytes); err != nil {
return err
}

View File

@@ -78,6 +78,13 @@ type tableMetadataInternal struct {
// Utility functions
// isValidBucketName validates bucket name characters
// Bucket names must contain only lowercase letters, numbers, hyphens, and underscores
func isValidBucketName(name string) bool {
pattern := regexp.MustCompile(`^[a-z0-9_-]+$`)
return pattern.MatchString(name)
}
// generateVersionToken generates a unique version token
func generateVersionToken() string {
return fmt.Sprintf("%d", time.Now().UnixNano())