s3tables: support multi-level namespace normalization

This commit is contained in:
Chris Lu
2026-02-09 19:42:31 -08:00
parent 0b80f055c2
commit be26ce74ce
10 changed files with 345 additions and 144 deletions

View File

@@ -231,11 +231,23 @@ func parseOptionalNamespace(r *http.Request, name string) []string {
if value == "" {
return nil
}
if _, err := s3tables.ValidateNamespace([]string{value}); err != nil {
parts, err := s3tables.ParseNamespace(value)
if err != nil {
glog.V(1).Infof("invalid namespace value for %s: %q: %v", name, value, err)
return nil
}
return []string{value}
return parts
}
func parseRequiredNamespacePathParam(r *http.Request, name string) ([]string, error) {
value, err := getDecodedPathParam(r, name)
if err != nil {
return nil, err
}
if value == "" {
return nil, fmt.Errorf("%s is required", name)
}
return s3tables.ParseNamespace(value)
}
// parseTagKeys handles tag key parsing from query parameters.
@@ -352,19 +364,13 @@ func buildGetNamespaceRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
return &s3tables.GetNamespaceRequest{
TableBucketARN: tableBucketARN,
Namespace: []string{namespace},
Namespace: namespace,
}, nil
}
@@ -373,19 +379,13 @@ func buildDeleteNamespaceRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
return &s3tables.DeleteNamespaceRequest{
TableBucketARN: tableBucketARN,
Namespace: []string{namespace},
Namespace: namespace,
}, nil
}
@@ -398,18 +398,12 @@ func buildCreateTableRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
req.TableBucketARN = tableBucketARN
req.Namespace = []string{namespace}
req.Namespace = namespace
return &req, nil
}
@@ -453,16 +447,10 @@ func buildDeleteTableRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
name, err := getDecodedPathParam(r, "name")
if err != nil {
return nil, err
@@ -475,7 +463,7 @@ func buildDeleteTableRequest(r *http.Request) (interface{}, error) {
}
return &s3tables.DeleteTableRequest{
TableBucketARN: tableBucketARN,
Namespace: []string{namespace},
Namespace: namespace,
Name: name,
VersionToken: r.URL.Query().Get("versionToken"),
}, nil
@@ -490,16 +478,10 @@ func buildPutTablePolicyRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
name, err := getDecodedPathParam(r, "name")
if err != nil {
return nil, err
@@ -511,7 +493,7 @@ func buildPutTablePolicyRequest(r *http.Request) (interface{}, error) {
return nil, err
}
req.TableBucketARN = tableBucketARN
req.Namespace = []string{namespace}
req.Namespace = namespace
req.Name = name
return &req, nil
}
@@ -521,16 +503,10 @@ func buildGetTablePolicyRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
name, err := getDecodedPathParam(r, "name")
if err != nil {
return nil, err
@@ -543,7 +519,7 @@ func buildGetTablePolicyRequest(r *http.Request) (interface{}, error) {
}
return &s3tables.GetTablePolicyRequest{
TableBucketARN: tableBucketARN,
Namespace: []string{namespace},
Namespace: namespace,
Name: name,
}, nil
}
@@ -553,16 +529,10 @@ func buildDeleteTablePolicyRequest(r *http.Request) (interface{}, error) {
if err != nil {
return nil, err
}
namespace, err := getDecodedPathParam(r, "namespace")
namespace, err := parseRequiredNamespacePathParam(r, "namespace")
if err != nil {
return nil, err
}
if namespace == "" {
return nil, fmt.Errorf("namespace is required")
}
if _, err := s3tables.ValidateNamespace([]string{namespace}); err != nil {
return nil, err
}
name, err := getDecodedPathParam(r, "name")
if err != nil {
return nil, err
@@ -575,7 +545,7 @@ func buildDeleteTablePolicyRequest(r *http.Request) (interface{}, error) {
}
return &s3tables.DeleteTablePolicyRequest{
TableBucketARN: tableBucketARN,
Namespace: []string{namespace},
Namespace: namespace,
Name: name,
}, nil
}