Skip to content

Commit

Permalink
URL encode the Destination: header for server side COPY
Browse files Browse the repository at this point in the history
According to the documentation for object COPY:

https://developer.openstack.org/api-ref/object-store/

> Destination header string
>
> The container and object name of the destination object in the form
> of /container/object. You must UTF-8-encode and then URL-encode the
> names of the destination container and object before you include
> them in this header.

Before this patch it was not URL encoded which is out of
specification.  This causes problems doing server side copies of files
with valid URL escape codes in, (eg `%32`).
  • Loading branch information
ncw committed Aug 24, 2018
1 parent bd8b704 commit d9f1a98
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
11 changes: 10 additions & 1 deletion swift.go
Expand Up @@ -2079,6 +2079,15 @@ func (c *Connection) ObjectUpdate(container string, objectName string, h Headers
return err
}

// urlPathEscape escapes URL path the in string using URL escaping rules
//
// This mimics url.PathEscape which only available from go 1.8
func urlPathEscape(in string) string {
var u url.URL
u.Path = in
return u.String()
}

// ObjectCopy does a server side copy of an object to a new position
//
// All metadata is preserved. If metadata is set in the headers then
Expand All @@ -2091,7 +2100,7 @@ func (c *Connection) ObjectUpdate(container string, objectName string, h Headers
func (c *Connection) ObjectCopy(srcContainer string, srcObjectName string, dstContainer string, dstObjectName string, h Headers) (headers Headers, err error) {
// Meta stuff
extraHeaders := map[string]string{
"Destination": dstContainer + "/" + dstObjectName,
"Destination": urlPathEscape(dstContainer + "/" + dstObjectName),
}
for key, value := range h {
extraHeaders[key] = value
Expand Down
14 changes: 14 additions & 0 deletions swift_test.go
Expand Up @@ -1479,6 +1479,20 @@ func TestObjectCopy(t *testing.T) {
}
}

func TestObjectCopyDifficultName(t *testing.T) {
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
const dest = OBJECT + "?param %30%31%32 £100"
_, err := c.ObjectCopy(CONTAINER, OBJECT, CONTAINER, dest, nil)
if err != nil {
t.Fatal(err)
}
err = c.ObjectDelete(CONTAINER, dest)
if err != nil {
t.Fatal(err)
}
}

func TestObjectCopyWithMetadata(t *testing.T) {
c, rollback := makeConnectionWithObjectHeaders(t)
defer rollback()
Expand Down

0 comments on commit d9f1a98

Please sign in to comment.