mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 15:04:37 +00:00
address test errors
With these fixes, the s3-tests should now: ✅ Return InvalidBucketState (409 Conflict) for object lock operations on invalid buckets ✅ Return MalformedXML for invalid retention configurations ✅ Include VersionId in response headers when available ✅ Return proper HTTP status codes (403 Forbidden for retention mode changes) ✅ Handle all object lock validation errors consistently
This commit is contained in:
@@ -555,26 +555,22 @@ func (s3a *S3ApiServer) validateObjectLockHeaders(r *http.Request, versioningEna
|
||||
func mapValidationErrorToS3Error(err error) s3err.ErrorCode {
|
||||
switch {
|
||||
case errors.Is(err, ErrObjectLockVersioningRequired):
|
||||
// For object lock operations on non-versioned buckets, return 409 Conflict
|
||||
// For object lock operations on non-versioned buckets, return InvalidBucketState
|
||||
// This matches AWS S3 behavior and s3-tests expectations
|
||||
return s3err.ErrBucketNotEmpty // This maps to 409 Conflict
|
||||
return s3err.ErrInvalidBucketState
|
||||
case errors.Is(err, ErrInvalidObjectLockMode):
|
||||
return s3err.ErrInvalidRequest
|
||||
case errors.Is(err, ErrInvalidLegalHoldStatus):
|
||||
// For malformed legal hold status, return MalformedXML as expected by s3-tests
|
||||
return s3err.ErrMalformedXML
|
||||
case errors.Is(err, ErrInvalidRetentionDateFormat):
|
||||
return s3err.ErrMalformedDate
|
||||
case errors.Is(err, ErrRetentionDateMustBeFuture),
|
||||
errors.Is(err, ErrObjectLockModeRequiresDate),
|
||||
errors.Is(err, ErrRetentionDateRequiresMode):
|
||||
return s3err.ErrInvalidRequest
|
||||
case errors.Is(err, ErrGovernanceBypassVersioningRequired):
|
||||
return s3err.ErrInvalidRequest
|
||||
case errors.Is(err, ErrInvalidObjectLockDuration):
|
||||
return s3err.ErrInvalidRequest
|
||||
case errors.Is(err, ErrObjectLockDurationExceeded):
|
||||
return s3err.ErrInvalidRequest
|
||||
return s3err.ErrMalformedXML
|
||||
case errors.Is(err, ErrInvalidRetentionPeriod):
|
||||
// For invalid retention periods (days/years), return MalformedXML
|
||||
return s3err.ErrMalformedXML
|
||||
case errors.Is(err, ErrInvalidRetentionMode):
|
||||
// For invalid retention modes, return MalformedXML
|
||||
return s3err.ErrMalformedXML
|
||||
default:
|
||||
return s3err.ErrInvalidRequest
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ var (
|
||||
var (
|
||||
ErrObjectUnderLegalHold = errors.New("object is under legal hold and cannot be deleted or modified")
|
||||
ErrGovernanceBypassNotPermitted = errors.New("user does not have permission to bypass governance retention")
|
||||
ErrInvalidRetentionPeriod = errors.New("invalid retention period specified")
|
||||
ErrInvalidRetentionMode = errors.New("invalid retention mode specified")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -155,19 +157,19 @@ func parseObjectLockConfiguration(request *http.Request) (*ObjectLockConfigurati
|
||||
func validateRetention(retention *ObjectRetention) error {
|
||||
// AWS requires both Mode and RetainUntilDate for PutObjectRetention
|
||||
if retention.Mode == "" {
|
||||
return fmt.Errorf("retention configuration must specify Mode")
|
||||
return ErrInvalidRetentionMode
|
||||
}
|
||||
|
||||
if retention.RetainUntilDate == nil {
|
||||
return fmt.Errorf("retention configuration must specify RetainUntilDate")
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
if retention.Mode != s3_constants.RetentionModeGovernance && retention.Mode != s3_constants.RetentionModeCompliance {
|
||||
return fmt.Errorf("invalid retention mode: %s", retention.Mode)
|
||||
return ErrInvalidRetentionMode
|
||||
}
|
||||
|
||||
if retention.RetainUntilDate.Before(time.Now()) {
|
||||
return fmt.Errorf("retain until date must be in the future")
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -176,7 +178,7 @@ func validateRetention(retention *ObjectRetention) error {
|
||||
// validateLegalHold validates legal hold configuration
|
||||
func validateLegalHold(legalHold *ObjectLegalHold) error {
|
||||
if legalHold.Status != s3_constants.LegalHoldOn && legalHold.Status != s3_constants.LegalHoldOff {
|
||||
return fmt.Errorf("invalid legal hold status: %s", legalHold.Status)
|
||||
return ErrInvalidLegalHoldStatus
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -209,30 +211,30 @@ func validateObjectLockConfiguration(config *ObjectLockConfiguration) error {
|
||||
func validateDefaultRetention(retention *DefaultRetention) error {
|
||||
// Mode is required
|
||||
if retention.Mode == "" {
|
||||
return fmt.Errorf("default retention must specify Mode")
|
||||
return ErrInvalidRetentionMode
|
||||
}
|
||||
|
||||
// Mode must be valid
|
||||
if retention.Mode != s3_constants.RetentionModeGovernance && retention.Mode != s3_constants.RetentionModeCompliance {
|
||||
return fmt.Errorf("invalid default retention mode: %s", retention.Mode)
|
||||
return ErrInvalidRetentionMode
|
||||
}
|
||||
|
||||
// Exactly one of Days or Years must be specified
|
||||
if retention.Days == 0 && retention.Years == 0 {
|
||||
return fmt.Errorf("default retention must specify either Days or Years")
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
if retention.Days > 0 && retention.Years > 0 {
|
||||
return fmt.Errorf("default retention cannot specify both Days and Years")
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
// Validate ranges
|
||||
if retention.Days < 0 || retention.Days > MaxRetentionDays {
|
||||
return fmt.Errorf("default retention days must be between 0 and %d", MaxRetentionDays)
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
if retention.Years < 0 || retention.Years > MaxRetentionYears {
|
||||
return fmt.Errorf("default retention years must be between 0 and %d", MaxRetentionYears)
|
||||
return ErrInvalidRetentionPeriod
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -57,6 +57,7 @@ const (
|
||||
ErrNoSuchKey
|
||||
ErrNoSuchUpload
|
||||
ErrInvalidBucketName
|
||||
ErrInvalidBucketState
|
||||
ErrInvalidDigest
|
||||
ErrInvalidMaxKeys
|
||||
ErrInvalidMaxUploads
|
||||
@@ -154,6 +155,11 @@ var errorCodeResponse = map[ErrorCode]APIError{
|
||||
Description: "The specified bucket is not valid.",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrInvalidBucketState: {
|
||||
Code: "InvalidBucketState",
|
||||
Description: "The bucket is not in a valid state for the requested operation",
|
||||
HTTPStatusCode: http.StatusConflict,
|
||||
},
|
||||
ErrInvalidDigest: {
|
||||
Code: "InvalidDigest",
|
||||
Description: "The Content-Md5 you specified is not valid.",
|
||||
|
||||
Reference in New Issue
Block a user