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:
@@ -24,12 +24,18 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
|
|||||||
return fmt.Errorf("name is required")
|
return fmt.Errorf("name is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate bucket name
|
// Validate bucket name length
|
||||||
if len(req.Name) < 3 || len(req.Name) > 63 {
|
if len(req.Name) < 3 || len(req.Name) > 63 {
|
||||||
h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "bucket name must be between 3 and 63 characters")
|
h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "bucket name must be between 3 and 63 characters")
|
||||||
return fmt.Errorf("invalid bucket name length")
|
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)
|
bucketPath := getTableBucketPath(req.Name)
|
||||||
|
|
||||||
// Check if bucket already exists
|
// Check if bucket already exists
|
||||||
@@ -39,12 +45,22 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
|
|||||||
Directory: TablesPath,
|
Directory: TablesPath,
|
||||||
Name: req.Name,
|
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
|
exists = true
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
if exists {
|
||||||
h.writeError(w, http.StatusConflict, ErrCodeBucketAlreadyExists, fmt.Sprintf("table bucket %s already exists", req.Name))
|
h.writeError(w, http.StatusConflict, ErrCodeBucketAlreadyExists, fmt.Sprintf("table bucket %s already exists", req.Name))
|
||||||
return fmt.Errorf("bucket already exists")
|
return fmt.Errorf("bucket already exists")
|
||||||
@@ -58,7 +74,12 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
|
|||||||
OwnerID: h.accountID,
|
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 {
|
err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
// Create bucket directory
|
// Create bucket directory
|
||||||
@@ -73,7 +94,10 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
// Set tags if provided
|
// Set tags if provided
|
||||||
if len(req.Tags) > 0 {
|
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 {
|
if err := h.setExtendedAttribute(client, bucketPath, ExtendedKeyTags, tagsBytes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,13 @@ type tableMetadataInternal struct {
|
|||||||
|
|
||||||
// Utility functions
|
// 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
|
// generateVersionToken generates a unique version token
|
||||||
func generateVersionToken() string {
|
func generateVersionToken() string {
|
||||||
return fmt.Sprintf("%d", time.Now().UnixNano())
|
return fmt.Sprintf("%d", time.Now().UnixNano())
|
||||||
|
|||||||
Reference in New Issue
Block a user