@@ -1319,6 +1319,70 @@ def post_object(url, token, container, name, headers, http_conn=None,
13191319 raise ClientException .from_response (resp , 'Object POST failed' , body )
13201320
13211321
1322+ def copy_object (url , token , container , name , destination = None ,
1323+ headers = None , fresh_metadata = None , http_conn = None ,
1324+ response_dict = None , service_token = None ):
1325+ """
1326+ Copy object
1327+
1328+ :param url: storage URL
1329+ :param token: auth token; if None, no token will be sent
1330+ :param container: container name that the source object is in
1331+ :param name: source object name
1332+ :param destination: The container and object name of the destination object
1333+ in the form of /container/object; if None, the copy
1334+ will use the source as the destination.
1335+ :param headers: additional headers to include in the request
1336+ :param fresh_metadata: Enables object creation that omits existing user
1337+ metadata, default None
1338+ :param http_conn: HTTP connection object (If None, it will create the
1339+ conn object)
1340+ :param response_dict: an optional dictionary into which to place
1341+ the response - status, reason and headers
1342+ :param service_token: service auth token
1343+ :raises ClientException: HTTP COPY request failed
1344+ """
1345+ if http_conn :
1346+ parsed , conn = http_conn
1347+ else :
1348+ parsed , conn = http_connection (url )
1349+
1350+ path = parsed .path
1351+ container = quote (container )
1352+ name = quote (name )
1353+ path = '%s/%s/%s' % (path .rstrip ('/' ), container , name )
1354+
1355+ headers = dict (headers ) if headers else {}
1356+
1357+ if destination is not None :
1358+ headers ['Destination' ] = quote (destination )
1359+ elif container and name :
1360+ headers ['Destination' ] = '/%s/%s' % (container , name )
1361+
1362+ if token is not None :
1363+ headers ['X-Auth-Token' ] = token
1364+ if service_token is not None :
1365+ headers ['X-Service-Token' ] = service_token
1366+
1367+ if fresh_metadata is not None :
1368+ # remove potential fresh metadata headers
1369+ for fresh_hdr in [hdr for hdr in headers .keys ()
1370+ if hdr .lower () == 'x-fresh-metadata' ]:
1371+ headers .pop (fresh_hdr )
1372+ headers ['X-Fresh-Metadata' ] = 'true' if fresh_metadata else 'false'
1373+
1374+ conn .request ('COPY' , path , '' , headers )
1375+ resp = conn .getresponse ()
1376+ body = resp .read ()
1377+ http_log (('%s%s' % (url .replace (parsed .path , '' ), path ), 'COPY' ,),
1378+ {'headers' : headers }, resp , body )
1379+
1380+ store_response (resp , response_dict )
1381+
1382+ if resp .status < 200 or resp .status >= 300 :
1383+ raise ClientException .from_response (resp , 'Object COPY failed' , body )
1384+
1385+
13221386def delete_object (url , token = None , container = None , name = None , http_conn = None ,
13231387 headers = None , proxy = None , query_string = None ,
13241388 response_dict = None , service_token = None ):
@@ -1711,6 +1775,13 @@ def post_object(self, container, obj, headers, response_dict=None):
17111775 return self ._retry (None , post_object , container , obj , headers ,
17121776 response_dict = response_dict )
17131777
1778+ def copy_object (self , container , obj , destination = None , headers = None ,
1779+ fresh_metadata = None , response_dict = None ):
1780+ """Wrapper for :func:`copy_object`"""
1781+ return self ._retry (None , copy_object , container , obj , destination ,
1782+ headers , fresh_metadata ,
1783+ response_dict = response_dict )
1784+
17141785 def delete_object (self , container , obj , query_string = None ,
17151786 response_dict = None ):
17161787 """Wrapper for :func:`delete_object`"""
0 commit comments