mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-12 23:09:33 +01:00
s3api: always write XML timestamps with three fractional digits (#11520)
CopyObject responses carried LastModified values such as
"2026-09-29T20:30:04.56Z": trailing zeros of the fractional seconds were
trimmed, and a whole-second value had no fraction at all. AWS S3 always
writes exactly three digits ("...04.560Z"), and clients that parse with a
fixed-width pattern reject anything else. minio-java 8.6.0
(yyyy-MM-dd'T'HH:mm:ss.SSS'Z') throws DateTimeParseException, so roughly
one CopyObject in ten fails on the client even though the copy succeeded.
Two causes:
- xsdDateTime marshalled with "2006-01-02T15:04:05.999999999", which
drops trailing zeros. It now writes UTC with ".000Z".
- CopyObjectResult.MarshalXML had a pointer receiver, but the handlers
pass the result by value, so encoding/xml never called it and fell back
to time.Time's RFC 3339 encoding. It now has a value receiver.
CopyPartResult had no custom marshaller at all; it now uses xsdDateTime.
Follow-up to #8394 / #8398, which truncated these timestamps to
milliseconds but kept the trimmed format.
This commit is contained in:
1 parent
9a454bbe2b
commit
38ce95d960
4 files changed
+84
-4
No files matched your search
@@ -623,13 +623,16 @@ type CopyObjectResult struct {
|
||||
ETag string `xml:"ETag"`
|
||||
}
|
||||
|
||||
func (t *CopyObjectResult) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
// MarshalXML has a value receiver: handlers pass CopyObjectResult by value, and
|
||||
// encoding/xml does not call a pointer-receiver MarshalXML on a non-addressable
|
||||
// value, which silently fell back to time.Time's RFC 3339 encoding.
|
||||
func (t CopyObjectResult) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
type T CopyObjectResult
|
||||
var layout struct {
|
||||
*T
|
||||
LastModified *xsdDateTime `xml:"LastModified"`
|
||||
}
|
||||
layout.T = (*T)(t)
|
||||
layout.T = (*T)(&t)
|
||||
layout.LastModified = (*xsdDateTime)(&layout.T.LastModified)
|
||||
return e.EncodeElement(layout, start)
|
||||
}
|
||||
@@ -1512,8 +1515,15 @@ type xsdDateTime time.Time
|
||||
func (t *xsdDateTime) UnmarshalText(text []byte) error {
|
||||
return _unmarshalTime(text, (*time.Time)(t), "2006-01-02T15:04:05.999999999")
|
||||
}
|
||||
|
||||
// s3TimestampFormat is the timestamp layout AWS S3 uses in XML responses:
|
||||
// UTC with exactly three fractional digits. Trimming trailing zeros (".56Z",
|
||||
// or no fraction at all) breaks clients that parse with a fixed-width pattern,
|
||||
// e.g. minio-java's "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'".
|
||||
const s3TimestampFormat = "2006-01-02T15:04:05.000Z"
|
||||
|
||||
func (t xsdDateTime) MarshalText() ([]byte, error) {
|
||||
return _marshalTime((time.Time)(t), "2006-01-02T15:04:05.999999999")
|
||||
return []byte((time.Time)(t).UTC().Format(s3TimestampFormat)), nil
|
||||
}
|
||||
func (t xsdDateTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
if (time.Time)(t).IsZero() {
|
||||
|
||||
Reference in new issue
Block a user