diff --git a/weed/s3api/s3tables/handler_bucket_create.go b/weed/s3api/s3tables/handler_bucket_create.go index d146f7907..c5864f991 100644 --- a/weed/s3api/s3tables/handler_bucket_create.go +++ b/weed/s3api/s3tables/handler_bucket_create.go @@ -2,6 +2,7 @@ package s3tables import ( "encoding/json" + "errors" "fmt" "net/http" "time" @@ -47,17 +48,17 @@ func (h *S3TablesHandler) handleCreateTableBucket(w http.ResponseWriter, r *http // Check if bucket already exists exists := false err := filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { - resp, err := client.LookupDirectoryEntry(r.Context(), &filer_pb.LookupDirectoryEntryRequest{ + _, err := filer_pb.LookupEntry(r.Context(), client, &filer_pb.LookupDirectoryEntryRequest{ Directory: TablesPath, Name: req.Name, }) if err != nil { - // Not found is expected when creating a new bucket - return nil - } - if resp.Entry != nil { - exists = true + if errors.Is(err, filer_pb.ErrNotFound) { + return nil + } + return err } + exists = true return nil }) diff --git a/weed/s3api/s3tables/handler_bucket_get_list_delete.go b/weed/s3api/s3tables/handler_bucket_get_list_delete.go index 9c677d0d7..56bebb49a 100644 --- a/weed/s3api/s3tables/handler_bucket_get_list_delete.go +++ b/weed/s3api/s3tables/handler_bucket_get_list_delete.go @@ -48,7 +48,7 @@ func (h *S3TablesHandler) handleGetTableBucket(w http.ResponseWriter, r *http.Re }) if err != nil { - if errors.Is(err, ErrNotFound) { + if errors.Is(err, filer_pb.ErrNotFound) { h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) } else { h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to get table bucket: %v", err)) @@ -108,6 +108,9 @@ func (h *S3TablesHandler) handleListTableBuckets(w http.ResponseWriter, r *http. if respErr != nil { break } + if entry.Entry == nil { + continue + } hasMore = true lastFileName = entry.Entry.Name @@ -157,7 +160,7 @@ func (h *S3TablesHandler) handleListTableBuckets(w http.ResponseWriter, r *http. if err != nil { // Check if it's a "not found" error - return empty list in that case - if errors.Is(err, ErrNotFound) { + if errors.Is(err, filer_pb.ErrNotFound) { buckets = []TableBucketSummary{} } else { // For other errors, return error response @@ -228,7 +231,7 @@ func (h *S3TablesHandler) handleDeleteTableBucket(w http.ResponseWriter, r *http }) if err != nil { - if !errors.Is(err, ErrNotFound) { + if !errors.Is(err, filer_pb.ErrNotFound) { h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list bucket entries: %v", err)) return err } diff --git a/weed/s3api/s3tables/handler_namespace.go b/weed/s3api/s3tables/handler_namespace.go index 077b7bbe1..9634bc29d 100644 --- a/weed/s3api/s3tables/handler_namespace.go +++ b/weed/s3api/s3tables/handler_namespace.go @@ -50,31 +50,34 @@ func (h *S3TablesHandler) handleCreateNamespace(w http.ResponseWriter, r *http.R // Check if table bucket exists bucketPath := getTableBucketPath(bucketName) - var bucketExists bool err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, bucketPath, ExtendedKeyMetadata) - bucketExists = err == nil - return nil + return err }) - if !bucketExists { - h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) - return fmt.Errorf("bucket not found") + if err != nil { + if errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check table bucket: %v", err)) + } + return err } namespacePath := getNamespacePath(bucketName, namespaceName) // Check if namespace already exists - exists := false err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, namespacePath, ExtendedKeyMetadata) - exists = err == nil - return nil + return err }) - if exists { + if err == nil { h.writeError(w, http.StatusConflict, ErrCodeNamespaceAlreadyExists, fmt.Sprintf("namespace %s already exists", namespaceName)) return fmt.Errorf("namespace already exists") + } else if !errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check namespace: %v", err)) + return err } // Create the namespace @@ -231,10 +234,13 @@ func (h *S3TablesHandler) handleListNamespaces(w http.ResponseWriter, r *http.Re if respErr != nil { break } + if entry.Entry == nil { + continue + } hasMore = true lastFileName = entry.Entry.Name - if entry.Entry == nil || !entry.Entry.IsDirectory { + if !entry.Entry.IsDirectory { continue } @@ -278,7 +284,12 @@ func (h *S3TablesHandler) handleListNamespaces(w http.ResponseWriter, r *http.Re }) if err != nil { - namespaces = []NamespaceSummary{} + if errors.Is(err, filer_pb.ErrNotFound) { + namespaces = []NamespaceSummary{} + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list namespaces: %v", err)) + return err + } } resp := &ListNamespacesResponse{ @@ -349,7 +360,7 @@ func (h *S3TablesHandler) handleDeleteNamespace(w http.ResponseWriter, r *http.R }) if err != nil { - if !errors.Is(err, ErrNotFound) { + if !errors.Is(err, filer_pb.ErrNotFound) { h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to list namespace entries: %v", err)) return err } diff --git a/weed/s3api/s3tables/handler_policy.go b/weed/s3api/s3tables/handler_policy.go index 97e250273..d16ab879a 100644 --- a/weed/s3api/s3tables/handler_policy.go +++ b/weed/s3api/s3tables/handler_policy.go @@ -35,16 +35,18 @@ func (h *S3TablesHandler) handlePutTableBucketPolicy(w http.ResponseWriter, r *h // Check if bucket exists bucketPath := getTableBucketPath(bucketName) - var bucketExists bool err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, bucketPath, ExtendedKeyMetadata) - bucketExists = err == nil - return nil + return err }) - if !bucketExists { - h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) - return fmt.Errorf("bucket not found") + if err != nil { + if errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check table bucket: %v", err)) + } + return err } // Write policy @@ -125,7 +127,7 @@ func (h *S3TablesHandler) handleDeleteTableBucketPolicy(w http.ResponseWriter, r return h.deleteExtendedAttribute(r.Context(), client, bucketPath, ExtendedKeyPolicy) }) - if err != nil && !errors.Is(err, ErrNotFound) && !errors.Is(err, ErrAttributeNotFound) { + if err != nil && !errors.Is(err, filer_pb.ErrNotFound) && !errors.Is(err, ErrAttributeNotFound) { h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, "failed to delete table bucket policy") return err } @@ -166,16 +168,18 @@ func (h *S3TablesHandler) handlePutTablePolicy(w http.ResponseWriter, r *http.Re // Check if table exists tablePath := getTablePath(bucketName, namespaceName, req.Name) - var tableExists bool err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, tablePath, ExtendedKeyMetadata) - tableExists = err == nil - return nil + return err }) - if !tableExists { - h.writeError(w, http.StatusNotFound, ErrCodeNoSuchTable, fmt.Sprintf("table %s not found", req.Name)) - return fmt.Errorf("table not found") + if err != nil { + if errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchTable, fmt.Sprintf("table %s not found", req.Name)) + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check table: %v", err)) + } + return err } // Write policy @@ -268,7 +272,7 @@ func (h *S3TablesHandler) handleDeleteTablePolicy(w http.ResponseWriter, r *http return h.deleteExtendedAttribute(r.Context(), client, tablePath, ExtendedKeyPolicy) }) - if err != nil && !errors.Is(err, ErrNotFound) && !errors.Is(err, ErrAttributeNotFound) { + if err != nil && !errors.Is(err, filer_pb.ErrNotFound) && !errors.Is(err, ErrAttributeNotFound) { h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, "failed to delete table policy") return err } diff --git a/weed/s3api/s3tables/handler_table.go b/weed/s3api/s3tables/handler_table.go index dc059d8f1..6b5858580 100644 --- a/weed/s3api/s3tables/handler_table.go +++ b/weed/s3api/s3tables/handler_table.go @@ -3,6 +3,7 @@ package s3tables import ( "context" "encoding/json" + "errors" "fmt" "net/http" "strings" @@ -57,34 +58,48 @@ func (h *S3TablesHandler) handleCreateTable(w http.ResponseWriter, r *http.Reque h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "table name must be between 1 and 255 characters") return fmt.Errorf("invalid table name length") } + if req.Name == "." || req.Name == ".." || strings.Contains(req.Name, "/") { + h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "invalid table name: cannot be '.', '..' or contain '/'") + return fmt.Errorf("invalid table name") + } + for _, ch := range req.Name { + if (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_' { + continue + } + h.writeError(w, http.StatusBadRequest, ErrCodeInvalidRequest, "invalid table name: only 'a-z', '0-9', and '_' are allowed") + return fmt.Errorf("invalid table name") + } // Check if namespace exists namespacePath := getNamespacePath(bucketName, namespaceName) - var namespaceExists bool err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, namespacePath, ExtendedKeyMetadata) - namespaceExists = err == nil - return nil + return err }) - if !namespaceExists { - h.writeError(w, http.StatusNotFound, ErrCodeNoSuchNamespace, fmt.Sprintf("namespace %s not found", namespaceName)) - return fmt.Errorf("namespace not found") + if err != nil { + if errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchNamespace, fmt.Sprintf("namespace %s not found", namespaceName)) + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check namespace: %v", err)) + } + return err } tablePath := getTablePath(bucketName, namespaceName, req.Name) // Check if table already exists - exists := false err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, tablePath, ExtendedKeyMetadata) - exists = err == nil - return nil + return err }) - if exists { + if err == nil { h.writeError(w, http.StatusConflict, ErrCodeTableAlreadyExists, fmt.Sprintf("table %s already exists", req.Name)) return fmt.Errorf("table already exists") + } else if !errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check table: %v", err)) + return err } // Create the table @@ -299,10 +314,13 @@ func (h *S3TablesHandler) listTablesInNamespaceWithClient(ctx context.Context, c if respErr != nil { break } + if entry.Entry == nil { + continue + } hasMore = true lastFileName = entry.Entry.Name - if entry.Entry == nil || !entry.Entry.IsDirectory { + if !entry.Entry.IsDirectory { continue } @@ -373,10 +391,13 @@ func (h *S3TablesHandler) listTablesInAllNamespaces(ctx context.Context, filerCl if respErr != nil { break } + if entry.Entry == nil { + continue + } hasMore = true lastFileName = entry.Entry.Name - if entry.Entry == nil || !entry.Entry.IsDirectory { + if !entry.Entry.IsDirectory { continue } @@ -434,16 +455,18 @@ func (h *S3TablesHandler) handleDeleteTable(w http.ResponseWriter, r *http.Reque tablePath := getTablePath(bucketName, namespaceName, req.Name) // Check if table exists - var tableExists bool err = filerClient.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error { _, err := h.getExtendedAttribute(r.Context(), client, tablePath, ExtendedKeyMetadata) - tableExists = err == nil - return nil + return err }) - if !tableExists { - h.writeError(w, http.StatusNotFound, ErrCodeNoSuchTable, fmt.Sprintf("table %s not found", req.Name)) - return fmt.Errorf("table not found") + if err != nil { + if errors.Is(err, filer_pb.ErrNotFound) { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchTable, fmt.Sprintf("table %s not found", req.Name)) + } else { + h.writeError(w, http.StatusInternalServerError, ErrCodeInternalError, fmt.Sprintf("failed to check table: %v", err)) + } + return err } // Delete the table