Browse Source

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
pull/6997/head
chrislu 5 months ago
parent
commit
0123abe49b
  1. 22
      weed/s3api/s3api_object_handlers_put.go
  2. 24
      weed/s3api/s3api_object_retention.go
  3. 6
      weed/s3api/s3err/s3api_errors.go

22
weed/s3api/s3api_object_handlers_put.go

@ -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
}

24
weed/s3api/s3api_object_retention.go

@ -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

6
weed/s3api/s3err/s3api_errors.go

@ -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.",

Loading…
Cancel
Save