diff --git a/swift.go b/swift.go index cdb79d908..5f103ec3d 100644 --- a/swift.go +++ b/swift.go @@ -2105,10 +2105,10 @@ func (c *Connection) objectBase(container string, objectName string) (info Objec // X-Delete-At or X-Delete-After for expiring objects. // // You cannot use this to change any of the object's other headers -// such as Content-Type, ETag, etc. +// such as ETag, etc. // // Refer to copying an object when you need to update metadata or -// other headers such as Content-Type or CORS headers. +// other headers such as CORS headers. // // May return ObjectNotFound. func (c *Connection) ObjectUpdate(container string, objectName string, h Headers) error { @@ -2175,11 +2175,12 @@ func (c *Connection) ObjectMove(srcContainer string, srcObjectName string, dstCo return c.ObjectDelete(srcContainer, srcObjectName) } -// ObjectUpdateContentType updates the content type of an object +// ObjectUpdateContentType updates the content type of an object while +// keeping current custom metadata. // -// This is a convenience method which calls ObjectCopy -// -// All other metadata is preserved. +// This is a convenience method which calls ObjectCopy, which causes data movement. +// Content-Type can also be updated with ObjectUpdate which updates metadata +// in place, without need of data movement in the cluster. func (c *Connection) ObjectUpdateContentType(container string, objectName string, contentType string) (err error) { h := Headers{"Content-Type": contentType} _, err = c.ObjectCopy(container, objectName, container, objectName, h) diff --git a/swift_test.go b/swift_test.go index be722cefb..881207fb7 100644 --- a/swift_test.go +++ b/swift_test.go @@ -41,6 +41,7 @@ var ( srv *swifttest.SwiftServer m1 = swift.Metadata{"Hello": "1", "potato-Salad": "2"} m2 = swift.Metadata{"hello": "", "potato-salad": ""} + m3 = swift.Metadata{"sweet-potato-salad": "1"} skipVersionTests = false ) @@ -1304,6 +1305,29 @@ func TestObjectUpdate2(t *testing.T) { compareMaps(t, headers.ObjectMetadata(), map[string]string{"hello": "", "potato-salad": ""}) } +func TestObjectUpdate3(t *testing.T) { + c, rollback := makeConnectionWithObjectHeaders(t) + defer rollback() + + // sanity + _, headers, err := c.Object(CONTAINER, OBJECT) + if err != nil { + t.Fatal(err) + } + compareMaps(t, headers.ObjectMetadata(), map[string]string{"hello": "1", "potato-salad": "1"}) + + // update with new headers + err = c.ObjectUpdate(CONTAINER, OBJECT, m3.ObjectHeaders()) + if err != nil { + t.Fatal(err) + } + _, headers, err = c.Object(CONTAINER, OBJECT) + if err != nil { + t.Fatal(err) + } + compareMaps(t, headers.ObjectMetadata(), map[string]string{"sweet-potato-salad": "1"}) +} + func TestContainers(t *testing.T) { c, rollback := makeConnectionWithObjectHeaders(t) defer rollback() @@ -1612,10 +1636,14 @@ func TestObjectMove(t *testing.T) { func TestObjectUpdateContentType(t *testing.T) { c, rollback := makeConnectionWithObjectHeaders(t) defer rollback() + + // to maintain backwards-compatibility update content-type with + // ObjectUpdateContentType, which copies object in place err := c.ObjectUpdateContentType(CONTAINER, OBJECT, "text/potato") if err != nil { t.Fatal(err) } + // Re-read the metadata to see if it is correct _, headers, err := c.Object(CONTAINER, OBJECT) if err != nil { @@ -1624,7 +1652,27 @@ func TestObjectUpdateContentType(t *testing.T) { if headers["Content-Type"] != "text/potato" { t.Error("Didn't change content type") } + + // ObjectUpdateContentType keeps old metadata because copy was used compareMaps(t, headers.ObjectMetadata(), map[string]string{"hello": "1", "potato-salad": "2"}) + + // Now update content-type with ObjectUpdate + // Note, old metadata is lost if not sent again + h := swift.Headers{"Content-Type": "text/sweet-potato", "X-Object-Meta-Sweet-Potato-Salad": "1"} + err = c.ObjectUpdate(CONTAINER, OBJECT, h) + if err != nil { + t.Fatal(err) + } + + // Re-read the metadata to see if it is correct + _, headers, err = c.Object(CONTAINER, OBJECT) + if err != nil { + t.Fatal(err) + } + if headers["Content-Type"] != "text/sweet-potato" { + t.Error("Didn't change content type") + } + compareMaps(t, headers.ObjectMetadata(), map[string]string{"sweet-potato-salad": "1"}) } func TestVersionContainerCreate(t *testing.T) {