diff --git a/.github/workflows/system.yml b/.github/workflows/system.yml index 89bfdcf..d5b9796 100644 --- a/.github/workflows/system.yml +++ b/.github/workflows/system.yml @@ -123,7 +123,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 'stable' + go-version: "stable" id: go - name: Get Dependencies @@ -148,6 +148,7 @@ jobs: - name: Install xmllint (for rest) run: | + sudo apt-get update sudo apt-get install libxml2-utils # see https://github.com/versity/versitygw/issues/1034 diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 4ca6a52..d8bf78c 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -821,7 +821,7 @@ func (p *Posix) isObjDeleteMarker(bucket, object string) (bool, error) { // delete markers from the versioning directory and returns func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { return func(path, versionIdMarker string, pastVersionIdMarker *bool, availableObjCount int, d fs.DirEntry) (*backend.ObjVersionFuncResult, error) { - var objects []types.ObjectVersion + var objects []s3response.ObjectVersion var delMarkers []types.DeleteMarkerEntry // if the number of available objects is 0, return truncated response if availableObjCount <= 0 { @@ -856,7 +856,7 @@ func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { size := int64(0) versionId := "null" - objects = append(objects, types.ObjectVersion{ + objects = append(objects, s3response.ObjectVersion{ ETag: &etag, Key: &key, LastModified: backend.GetTimePtr(fi.ModTime()), @@ -924,7 +924,7 @@ func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { return nil, fmt.Errorf("get checksum: %w", err) } - objects = append(objects, types.ObjectVersion{ + objects = append(objects, s3response.ObjectVersion{ ETag: &etag, Key: &path, LastModified: backend.GetTimePtr(fi.ModTime()), @@ -977,7 +977,7 @@ func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { // First find the null versionId object(if exists) // before starting the object versions listing - var nullVersionIdObj *types.ObjectVersion + var nullVersionIdObj *s3response.ObjectVersion var nullObjDelMarker *types.DeleteMarkerEntry nf, err := os.Stat(filepath.Join(versionPath, nullVersionId)) if err != nil && !errors.Is(err, fs.ErrNotExist) { @@ -1015,7 +1015,7 @@ func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { return nil, fmt.Errorf("get checksum: %w", err) } - nullVersionIdObj = &types.ObjectVersion{ + nullVersionIdObj = &s3response.ObjectVersion{ ETag: &etag, Key: &path, LastModified: backend.GetTimePtr(nf.ModTime()), @@ -1136,7 +1136,7 @@ func (p *Posix) fileToObjVersions(bucket string) backend.GetVersionsFunc { if err != nil && !errors.Is(err, meta.ErrNoSuchKey) { return nil, fmt.Errorf("get checksum: %w", err) } - objects = append(objects, types.ObjectVersion{ + objects = append(objects, s3response.ObjectVersion{ ETag: &etag, Key: &path, LastModified: backend.GetTimePtr(f.ModTime()), diff --git a/backend/s3proxy/s3.go b/backend/s3proxy/s3.go index 2ed6b36..7fbaf53 100644 --- a/backend/s3proxy/s3.go +++ b/backend/s3proxy/s3.go @@ -295,7 +295,7 @@ func (s *S3Proxy) ListObjectVersions(ctx context.Context, input *s3.ListObjectVe NextVersionIdMarker: out.NextVersionIdMarker, Prefix: out.Prefix, VersionIdMarker: input.VersionIdMarker, - Versions: out.Versions, + Versions: convertObjectVersions(out.Versions), }, nil } @@ -1718,3 +1718,24 @@ func convertObjects(objs []types.Object) []s3response.Object { return result } + +func convertObjectVersions(versions []types.ObjectVersion) []s3response.ObjectVersion { + result := make([]s3response.ObjectVersion, 0, len(versions)) + for _, v := range versions { + result = append(result, s3response.ObjectVersion{ + ChecksumAlgorithm: v.ChecksumAlgorithm, + ChecksumType: v.ChecksumType, + ETag: v.ETag, + IsLatest: v.IsLatest, + Key: v.Key, + LastModified: v.LastModified, + Owner: v.Owner, + RestoreStatus: v.RestoreStatus, + Size: v.Size, + StorageClass: v.StorageClass, + VersionId: v.VersionId, + }) + } + + return result +} diff --git a/backend/walk.go b/backend/walk.go index 0756957..17860c0 100644 --- a/backend/walk.go +++ b/backend/walk.go @@ -310,7 +310,7 @@ func contains(a string, strs []string) bool { type WalkVersioningResults struct { CommonPrefixes []types.CommonPrefix - ObjectVersions []types.ObjectVersion + ObjectVersions []s3response.ObjectVersion DelMarkers []types.DeleteMarkerEntry Truncated bool NextMarker string @@ -318,7 +318,7 @@ type WalkVersioningResults struct { } type ObjVersionFuncResult struct { - ObjectVersions []types.ObjectVersion + ObjectVersions []s3response.ObjectVersion DelMarkers []types.DeleteMarkerEntry NextVersionIdMarker string Truncated bool @@ -330,7 +330,7 @@ type GetVersionsFunc func(path, versionIdMarker string, pastVersionIdMarker *boo // ListObjectVersions action response func WalkVersions(ctx context.Context, fileSystem fs.FS, prefix, delimiter, keyMarker, versionIdMarker string, max int, getObj GetVersionsFunc, skipdirs []string) (WalkVersioningResults, error) { cpmap := cpMap{} - var objects []types.ObjectVersion + var objects []s3response.ObjectVersion var delMarkers []types.DeleteMarkerEntry var pastMarker bool diff --git a/s3response/s3response.go b/s3response/s3response.go index db2bd10..810f0b7 100644 --- a/s3response/s3response.go +++ b/s3response/s3response.go @@ -62,7 +62,7 @@ func (p Part) MarshalXML(e *xml.Encoder, start xml.StartElement) error { Alias: (*Alias)(&p), } - aux.LastModified = p.LastModified.UTC().Format(iso8601TimeFormat) + aux.LastModified = p.LastModified.UTC().Format(time.RFC3339) return e.EncodeElement(aux, start) } @@ -198,15 +198,14 @@ type Object struct { func (o Object) MarshalXML(e *xml.Encoder, start xml.StartElement) error { type Alias Object aux := &struct { - LastModified *string `xml:"LastModified,omitempty"` + LastModified string `xml:"LastModified,omitempty"` *Alias }{ Alias: (*Alias)(&o), } if o.LastModified != nil { - formattedTime := o.LastModified.UTC().Format(iso8601TimeFormat) - aux.LastModified = &formattedTime + aux.LastModified = o.LastModified.UTC().Format(time.RFC3339) } return e.EncodeElement(aux, start) @@ -233,7 +232,7 @@ func (u Upload) MarshalXML(e *xml.Encoder, start xml.StartElement) error { Alias: (*Alias)(&u), } - aux.Initiated = u.Initiated.UTC().Format(iso8601TimeFormat) + aux.Initiated = u.Initiated.UTC().Format(time.RFC3339) return e.EncodeElement(aux, start) } @@ -330,7 +329,7 @@ func (r ListAllMyBucketsEntry) MarshalXML(e *xml.Encoder, start xml.StartElement Alias: (*Alias)(&r), } - aux.CreationDate = r.CreationDate.UTC().Format(iso8601TimeFormat) + aux.CreationDate = r.CreationDate.UTC().Format(time.RFC3339) return e.EncodeElement(aux, start) } @@ -398,6 +397,21 @@ type CopyPartResult struct { CopySourceVersionId string `xml:"-"` } +func (r CopyPartResult) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias CopyPartResult + aux := &struct { + LastModified string `xml:"LastModified,omitempty"` + *Alias + }{ + Alias: (*Alias)(&r), + } + if !r.LastModified.IsZero() { + aux.LastModified = r.LastModified.UTC().Format(time.RFC3339) + } + + return e.EncodeElement(aux, start) +} + type CompleteMultipartUploadResult struct { XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult" json:"-"` Location *string @@ -466,7 +480,37 @@ type ListVersionsResult struct { NextVersionIdMarker *string Prefix *string VersionIdMarker *string - Versions []types.ObjectVersion `xml:"Version"` + Versions []ObjectVersion `xml:"Version"` +} + +type ObjectVersion struct { + ChecksumAlgorithm []types.ChecksumAlgorithm + ChecksumType types.ChecksumType + ETag *string + IsLatest *bool + Key *string + LastModified *time.Time + Owner *types.Owner + RestoreStatus *types.RestoreStatus + Size *int64 + StorageClass types.ObjectVersionStorageClass + VersionId *string +} + +func (o ObjectVersion) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias ObjectVersion + aux := &struct { + LastModified string `xml:"LastModified"` + *Alias + }{ + Alias: (*Alias)(&o), + } + + if o.LastModified != nil { + aux.LastModified = o.LastModified.UTC().Format(time.RFC3339) + } + + return e.EncodeElement(aux, start) } type GetBucketVersioningOutput struct {