diff options
Diffstat (limited to 'swiftclient/client.py')
-rw-r--r-- | swiftclient/client.py | 105 |
1 files changed, 96 insertions, 9 deletions
diff --git a/swiftclient/client.py b/swiftclient/client.py index f556afd..988c7d9 100644 --- a/swiftclient/client.py +++ b/swiftclient/client.py @@ -827,7 +827,8 @@ def post_account(url, token, headers, http_conn=None, response_dict=None, def get_container(url, token, container, marker=None, limit=None, prefix=None, delimiter=None, end_marker=None, path=None, http_conn=None, - full_listing=False, service_token=None, headers=None): + full_listing=False, service_token=None, headers=None, + query_string=None): """ Get a listing of objects for the container. @@ -846,6 +847,7 @@ def get_container(url, token, container, marker=None, limit=None, of 10000 listings :param service_token: service auth token :param headers: additional headers to include in the request + :param query_string: if set will be appended with '?' to generated path :returns: a tuple of (response headers, a list of objects) The response headers will be a dict and all header names will be lowercase. :raises ClientException: HTTP GET request failed @@ -889,6 +891,8 @@ def get_container(url, token, container, marker=None, limit=None, qs += '&end_marker=%s' % quote(end_marker) if path: qs += '&path=%s' % quote(path) + if query_string: + qs += '&%s' % query_string.lstrip('?') if service_token: headers['X-Service-Token'] = service_token method = 'GET' @@ -950,7 +954,7 @@ def head_container(url, token, container, http_conn=None, headers=None, def put_container(url, token, container, headers=None, http_conn=None, - response_dict=None, service_token=None): + response_dict=None, service_token=None, query_string=None): """ Create a container @@ -963,6 +967,7 @@ def put_container(url, token, container, headers=None, http_conn=None, :param response_dict: an optional dictionary into which to place the response - status, reason and headers :param service_token: service auth token + :param query_string: if set will be appended with '?' to generated path :raises ClientException: HTTP PUT request failed """ if http_conn: @@ -978,6 +983,8 @@ def put_container(url, token, container, headers=None, http_conn=None, headers['X-Service-Token'] = service_token if 'content-length' not in (k.lower() for k in headers): headers['Content-Length'] = '0' + if query_string: + path += '?' + query_string.lstrip('?') conn.request(method, path, '', headers) resp = conn.getresponse() body = resp.read() @@ -1031,7 +1038,8 @@ def post_container(url, token, container, headers, http_conn=None, def delete_container(url, token, container, http_conn=None, - response_dict=None, service_token=None): + response_dict=None, service_token=None, + query_string=None): """ Delete a container @@ -1043,6 +1051,7 @@ def delete_container(url, token, container, http_conn=None, :param response_dict: an optional dictionary into which to place the response - status, reason and headers :param service_token: service auth token + :param query_string: if set will be appended with '?' to generated path :raises ClientException: HTTP DELETE request failed """ if http_conn: @@ -1053,6 +1062,8 @@ def delete_container(url, token, container, http_conn=None, headers = {'X-Auth-Token': token} if service_token: headers['X-Service-Token'] = service_token + if query_string: + path += '?' + query_string.lstrip('?') method = 'DELETE' conn.request(method, path, '', headers) resp = conn.getresponse() @@ -1319,6 +1330,70 @@ def post_object(url, token, container, name, headers, http_conn=None, raise ClientException.from_response(resp, 'Object POST failed', body) +def copy_object(url, token, container, name, destination=None, + headers=None, fresh_metadata=None, http_conn=None, + response_dict=None, service_token=None): + """ + Copy object + + :param url: storage URL + :param token: auth token; if None, no token will be sent + :param container: container name that the source object is in + :param name: source object name + :param destination: The container and object name of the destination object + in the form of /container/object; if None, the copy + will use the source as the destination. + :param headers: additional headers to include in the request + :param fresh_metadata: Enables object creation that omits existing user + metadata, default None + :param http_conn: HTTP connection object (If None, it will create the + conn object) + :param response_dict: an optional dictionary into which to place + the response - status, reason and headers + :param service_token: service auth token + :raises ClientException: HTTP COPY request failed + """ + if http_conn: + parsed, conn = http_conn + else: + parsed, conn = http_connection(url) + + path = parsed.path + container = quote(container) + name = quote(name) + path = '%s/%s/%s' % (path.rstrip('/'), container, name) + + headers = dict(headers) if headers else {} + + if destination is not None: + headers['Destination'] = quote(destination) + elif container and name: + headers['Destination'] = '/%s/%s' % (container, name) + + if token is not None: + headers['X-Auth-Token'] = token + if service_token is not None: + headers['X-Service-Token'] = service_token + + if fresh_metadata is not None: + # remove potential fresh metadata headers + for fresh_hdr in [hdr for hdr in headers.keys() + if hdr.lower() == 'x-fresh-metadata']: + headers.pop(fresh_hdr) + headers['X-Fresh-Metadata'] = 'true' if fresh_metadata else 'false' + + conn.request('COPY', path, '', headers) + resp = conn.getresponse() + body = resp.read() + http_log(('%s%s' % (url.replace(parsed.path, ''), path), 'COPY',), + {'headers': headers}, resp, body) + + store_response(resp, response_dict) + + if resp.status < 200 or resp.status >= 300: + raise ClientException.from_response(resp, 'Object COPY failed', body) + + def delete_object(url, token=None, container=None, name=None, http_conn=None, headers=None, proxy=None, query_string=None, response_dict=None, service_token=None): @@ -1625,7 +1700,7 @@ class Connection(object): def get_container(self, container, marker=None, limit=None, prefix=None, delimiter=None, end_marker=None, path=None, - full_listing=False, headers=None): + full_listing=False, headers=None, query_string=None): """Wrapper for :func:`get_container`""" # TODO(unknown): With full_listing=True this will restart the entire # listing with each retry. Need to make a better version that just @@ -1633,22 +1708,27 @@ class Connection(object): return self._retry(None, get_container, container, marker=marker, limit=limit, prefix=prefix, delimiter=delimiter, end_marker=end_marker, path=path, - full_listing=full_listing, headers=headers) + full_listing=full_listing, headers=headers, + query_string=query_string) - def put_container(self, container, headers=None, response_dict=None): + def put_container(self, container, headers=None, response_dict=None, + query_string=None): """Wrapper for :func:`put_container`""" return self._retry(None, put_container, container, headers=headers, - response_dict=response_dict) + response_dict=response_dict, + query_string=query_string) def post_container(self, container, headers, response_dict=None): """Wrapper for :func:`post_container`""" return self._retry(None, post_container, container, headers, response_dict=response_dict) - def delete_container(self, container, response_dict=None): + def delete_container(self, container, response_dict=None, + query_string=None): """Wrapper for :func:`delete_container`""" return self._retry(None, delete_container, container, - response_dict=response_dict) + response_dict=response_dict, + query_string=query_string) def head_object(self, container, obj, headers=None): """Wrapper for :func:`head_object`""" @@ -1711,6 +1791,13 @@ class Connection(object): return self._retry(None, post_object, container, obj, headers, response_dict=response_dict) + def copy_object(self, container, obj, destination=None, headers=None, + fresh_metadata=None, response_dict=None): + """Wrapper for :func:`copy_object`""" + return self._retry(None, copy_object, container, obj, destination, + headers, fresh_metadata, + response_dict=response_dict) + def delete_object(self, container, obj, query_string=None, response_dict=None): """Wrapper for :func:`delete_object`""" |