| Index: third_party/boto/boto/s3/connection.py
 | 
| diff --git a/third_party/boto/boto/s3/connection.py b/third_party/boto/boto/s3/connection.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..28969e5e887244eebd4672903767f8e1611e09df
 | 
| --- /dev/null
 | 
| +++ b/third_party/boto/boto/s3/connection.py
 | 
| @@ -0,0 +1,540 @@
 | 
| +# Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
 | 
| +# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
 | 
| +# Copyright (c) 2010, Eucalyptus Systems, Inc.
 | 
| +# All rights reserved.
 | 
| +#
 | 
| +# Permission is hereby granted, free of charge, to any person obtaining a
 | 
| +# copy of this software and associated documentation files (the
 | 
| +# "Software"), to deal in the Software without restriction, including
 | 
| +# without limitation the rights to use, copy, modify, merge, publish, dis-
 | 
| +# tribute, sublicense, and/or sell copies of the Software, and to permit
 | 
| +# persons to whom the Software is furnished to do so, subject to the fol-
 | 
| +# lowing conditions:
 | 
| +#
 | 
| +# The above copyright notice and this permission notice shall be included
 | 
| +# in all copies or substantial portions of the Software.
 | 
| +#
 | 
| +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
| +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 | 
| +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 | 
| +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
| +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
| +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
| +# IN THE SOFTWARE.
 | 
| +
 | 
| +import xml.sax
 | 
| +import urllib
 | 
| +import base64
 | 
| +import time
 | 
| +
 | 
| +import boto.utils
 | 
| +from boto.connection import AWSAuthConnection
 | 
| +from boto import handler
 | 
| +from boto.s3.bucket import Bucket
 | 
| +from boto.s3.key import Key
 | 
| +from boto.resultset import ResultSet
 | 
| +from boto.exception import BotoClientError, S3ResponseError
 | 
| +
 | 
| +
 | 
| +def check_lowercase_bucketname(n):
 | 
| +    """
 | 
| +    Bucket names must not contain uppercase characters. We check for
 | 
| +    this by appending a lowercase character and testing with islower().
 | 
| +    Note this also covers cases like numeric bucket names with dashes.
 | 
| +
 | 
| +    >>> check_lowercase_bucketname("Aaaa")
 | 
| +    Traceback (most recent call last):
 | 
| +    ...
 | 
| +    BotoClientError: S3Error: Bucket names cannot contain upper-case
 | 
| +    characters when using either the sub-domain or virtual hosting calling
 | 
| +    format.
 | 
| +
 | 
| +    >>> check_lowercase_bucketname("1234-5678-9123")
 | 
| +    True
 | 
| +    >>> check_lowercase_bucketname("abcdefg1234")
 | 
| +    True
 | 
| +    """
 | 
| +    if not (n + 'a').islower():
 | 
| +        raise BotoClientError("Bucket names cannot contain upper-case " \
 | 
| +            "characters when using either the sub-domain or virtual " \
 | 
| +            "hosting calling format.")
 | 
| +    return True
 | 
| +
 | 
| +
 | 
| +def assert_case_insensitive(f):
 | 
| +    def wrapper(*args, **kwargs):
 | 
| +        if len(args) == 3 and check_lowercase_bucketname(args[2]):
 | 
| +            pass
 | 
| +        return f(*args, **kwargs)
 | 
| +    return wrapper
 | 
| +
 | 
| +
 | 
| +class _CallingFormat(object):
 | 
| +
 | 
| +    def get_bucket_server(self, server, bucket):
 | 
| +        return ''
 | 
| +
 | 
| +    def build_url_base(self, connection, protocol, server, bucket, key=''):
 | 
| +        url_base = '%s://' % protocol
 | 
| +        url_base += self.build_host(server, bucket)
 | 
| +        url_base += connection.get_path(self.build_path_base(bucket, key))
 | 
| +        return url_base
 | 
| +
 | 
| +    def build_host(self, server, bucket):
 | 
| +        if bucket == '':
 | 
| +            return server
 | 
| +        else:
 | 
| +            return self.get_bucket_server(server, bucket)
 | 
| +
 | 
| +    def build_auth_path(self, bucket, key=''):
 | 
| +        key = boto.utils.get_utf8_value(key)
 | 
| +        path = ''
 | 
| +        if bucket != '':
 | 
| +            path = '/' + bucket
 | 
| +        return path + '/%s' % urllib.quote(key)
 | 
| +
 | 
| +    def build_path_base(self, bucket, key=''):
 | 
| +        key = boto.utils.get_utf8_value(key)
 | 
| +        return '/%s' % urllib.quote(key)
 | 
| +
 | 
| +
 | 
| +class SubdomainCallingFormat(_CallingFormat):
 | 
| +
 | 
| +    @assert_case_insensitive
 | 
| +    def get_bucket_server(self, server, bucket):
 | 
| +        return '%s.%s' % (bucket, server)
 | 
| +
 | 
| +
 | 
| +class VHostCallingFormat(_CallingFormat):
 | 
| +
 | 
| +    @assert_case_insensitive
 | 
| +    def get_bucket_server(self, server, bucket):
 | 
| +        return bucket
 | 
| +
 | 
| +
 | 
| +class OrdinaryCallingFormat(_CallingFormat):
 | 
| +
 | 
| +    def get_bucket_server(self, server, bucket):
 | 
| +        return server
 | 
| +
 | 
| +    def build_path_base(self, bucket, key=''):
 | 
| +        key = boto.utils.get_utf8_value(key)
 | 
| +        path_base = '/'
 | 
| +        if bucket:
 | 
| +            path_base += "%s/" % bucket
 | 
| +        return path_base + urllib.quote(key)
 | 
| +
 | 
| +
 | 
| +class ProtocolIndependentOrdinaryCallingFormat(OrdinaryCallingFormat):
 | 
| +
 | 
| +    def build_url_base(self, connection, protocol, server, bucket, key=''):
 | 
| +        url_base = '//'
 | 
| +        url_base += self.build_host(server, bucket)
 | 
| +        url_base += connection.get_path(self.build_path_base(bucket, key))
 | 
| +        return url_base
 | 
| +
 | 
| +
 | 
| +class Location:
 | 
| +
 | 
| +    DEFAULT = ''  # US Classic Region
 | 
| +    EU = 'EU'
 | 
| +    USWest = 'us-west-1'
 | 
| +    USWest2 = 'us-west-2'
 | 
| +    SAEast = 'sa-east-1'
 | 
| +    APNortheast = 'ap-northeast-1'
 | 
| +    APSoutheast = 'ap-southeast-1'
 | 
| +    APSoutheast2 = 'ap-southeast-2'
 | 
| +
 | 
| +
 | 
| +class S3Connection(AWSAuthConnection):
 | 
| +
 | 
| +    DefaultHost = 's3.amazonaws.com'
 | 
| +    QueryString = 'Signature=%s&Expires=%d&AWSAccessKeyId=%s'
 | 
| +
 | 
| +    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
 | 
| +                 is_secure=True, port=None, proxy=None, proxy_port=None,
 | 
| +                 proxy_user=None, proxy_pass=None,
 | 
| +                 host=DefaultHost, debug=0, https_connection_factory=None,
 | 
| +                 calling_format=SubdomainCallingFormat(), path='/',
 | 
| +                 provider='aws', bucket_class=Bucket, security_token=None,
 | 
| +                 suppress_consec_slashes=True, anon=False,
 | 
| +                 validate_certs=None):
 | 
| +        self.calling_format = calling_format
 | 
| +        self.bucket_class = bucket_class
 | 
| +        self.anon = anon
 | 
| +        AWSAuthConnection.__init__(self, host,
 | 
| +                aws_access_key_id, aws_secret_access_key,
 | 
| +                is_secure, port, proxy, proxy_port, proxy_user, proxy_pass,
 | 
| +                debug=debug, https_connection_factory=https_connection_factory,
 | 
| +                path=path, provider=provider, security_token=security_token,
 | 
| +                suppress_consec_slashes=suppress_consec_slashes,
 | 
| +                validate_certs=validate_certs)
 | 
| +
 | 
| +    def _required_auth_capability(self):
 | 
| +        if self.anon:
 | 
| +            return ['anon']
 | 
| +        else:
 | 
| +            return ['s3']
 | 
| +
 | 
| +    def __iter__(self):
 | 
| +        for bucket in self.get_all_buckets():
 | 
| +            yield bucket
 | 
| +
 | 
| +    def __contains__(self, bucket_name):
 | 
| +        return not (self.lookup(bucket_name) is None)
 | 
| +
 | 
| +    def set_bucket_class(self, bucket_class):
 | 
| +        """
 | 
| +        Set the Bucket class associated with this bucket.  By default, this
 | 
| +        would be the boto.s3.key.Bucket class but if you want to subclass that
 | 
| +        for some reason this allows you to associate your new class.
 | 
| +
 | 
| +        :type bucket_class: class
 | 
| +        :param bucket_class: A subclass of Bucket that can be more specific
 | 
| +        """
 | 
| +        self.bucket_class = bucket_class
 | 
| +
 | 
| +    def build_post_policy(self, expiration_time, conditions):
 | 
| +        """
 | 
| +        Taken from the AWS book Python examples and modified for use with boto
 | 
| +        """
 | 
| +        assert isinstance(expiration_time, time.struct_time), \
 | 
| +            'Policy document must include a valid expiration Time object'
 | 
| +
 | 
| +        # Convert conditions object mappings to condition statements
 | 
| +
 | 
| +        return '{"expiration": "%s",\n"conditions": [%s]}' % \
 | 
| +            (time.strftime(boto.utils.ISO8601, expiration_time), ",".join(conditions))
 | 
| +
 | 
| +    def build_post_form_args(self, bucket_name, key, expires_in=6000,
 | 
| +                             acl=None, success_action_redirect=None,
 | 
| +                             max_content_length=None,
 | 
| +                             http_method='http', fields=None,
 | 
| +                             conditions=None, storage_class='STANDARD',
 | 
| +                             server_side_encryption=None):
 | 
| +        """
 | 
| +        Taken from the AWS book Python examples and modified for use with boto
 | 
| +        This only returns the arguments required for the post form, not the
 | 
| +        actual form.  This does not return the file input field which also
 | 
| +        needs to be added
 | 
| +
 | 
| +        :type bucket_name: string
 | 
| +        :param bucket_name: Bucket to submit to
 | 
| +
 | 
| +        :type key: string
 | 
| +        :param key:  Key name, optionally add ${filename} to the end to
 | 
| +            attach the submitted filename
 | 
| +
 | 
| +        :type expires_in: integer
 | 
| +        :param expires_in: Time (in seconds) before this expires, defaults
 | 
| +            to 6000
 | 
| +
 | 
| +        :type acl: string
 | 
| +        :param acl: A canned ACL.  One of:
 | 
| +            * private
 | 
| +            * public-read
 | 
| +            * public-read-write
 | 
| +            * authenticated-read
 | 
| +            * bucket-owner-read
 | 
| +            * bucket-owner-full-control
 | 
| +
 | 
| +        :type success_action_redirect: string
 | 
| +        :param success_action_redirect: URL to redirect to on success
 | 
| +
 | 
| +        :type max_content_length: integer
 | 
| +        :param max_content_length: Maximum size for this file
 | 
| +
 | 
| +        :type http_method: string
 | 
| +        :param http_method:  HTTP Method to use, "http" or "https"
 | 
| +
 | 
| +        :type storage_class: string
 | 
| +        :param storage_class: Storage class to use for storing the object.
 | 
| +            Valid values: STANDARD | REDUCED_REDUNDANCY
 | 
| +
 | 
| +        :type server_side_encryption: string
 | 
| +        :param server_side_encryption: Specifies server-side encryption
 | 
| +            algorithm to use when Amazon S3 creates an object.
 | 
| +            Valid values: None | AES256
 | 
| +
 | 
| +        :rtype: dict
 | 
| +        :return: A dictionary containing field names/values as well as
 | 
| +            a url to POST to
 | 
| +
 | 
| +            .. code-block:: python
 | 
| +
 | 
| +
 | 
| +        """
 | 
| +        if fields == None:
 | 
| +            fields = []
 | 
| +        if conditions == None:
 | 
| +            conditions = []
 | 
| +        expiration = time.gmtime(int(time.time() + expires_in))
 | 
| +
 | 
| +        # Generate policy document
 | 
| +        conditions.append('{"bucket": "%s"}' % bucket_name)
 | 
| +        if key.endswith("${filename}"):
 | 
| +            conditions.append('["starts-with", "$key", "%s"]' % key[:-len("${filename}")])
 | 
| +        else:
 | 
| +            conditions.append('{"key": "%s"}' % key)
 | 
| +        if acl:
 | 
| +            conditions.append('{"acl": "%s"}' % acl)
 | 
| +            fields.append({"name": "acl", "value": acl})
 | 
| +        if success_action_redirect:
 | 
| +            conditions.append('{"success_action_redirect": "%s"}' % success_action_redirect)
 | 
| +            fields.append({"name": "success_action_redirect", "value": success_action_redirect})
 | 
| +        if max_content_length:
 | 
| +            conditions.append('["content-length-range", 0, %i]' % max_content_length)
 | 
| +
 | 
| +        if self.provider.security_token:
 | 
| +            fields.append({'name': 'x-amz-security-token',
 | 
| +                           'value': self.provider.security_token})
 | 
| +            conditions.append('{"x-amz-security-token": "%s"}' % self.provider.security_token)
 | 
| +
 | 
| +        if storage_class:
 | 
| +            fields.append({'name': 'x-amz-storage-class',
 | 
| +                           'value': storage_class})
 | 
| +            conditions.append('{"x-amz-storage-class": "%s"}' % storage_class)
 | 
| +
 | 
| +        if server_side_encryption:
 | 
| +            fields.append({'name': 'x-amz-server-side-encryption',
 | 
| +                           'value': server_side_encryption})
 | 
| +            conditions.append('{"x-amz-server-side-encryption": "%s"}' % server_side_encryption)
 | 
| +
 | 
| +        policy = self.build_post_policy(expiration, conditions)
 | 
| +
 | 
| +        # Add the base64-encoded policy document as the 'policy' field
 | 
| +        policy_b64 = base64.b64encode(policy)
 | 
| +        fields.append({"name": "policy", "value": policy_b64})
 | 
| +
 | 
| +        # Add the AWS access key as the 'AWSAccessKeyId' field
 | 
| +        fields.append({"name": "AWSAccessKeyId",
 | 
| +                       "value": self.aws_access_key_id})
 | 
| +
 | 
| +        # Add signature for encoded policy document as the
 | 
| +        # 'signature' field
 | 
| +        signature = self._auth_handler.sign_string(policy_b64)
 | 
| +        fields.append({"name": "signature", "value": signature})
 | 
| +        fields.append({"name": "key", "value": key})
 | 
| +
 | 
| +        # HTTPS protocol will be used if the secure HTTP option is enabled.
 | 
| +        url = '%s://%s/' % (http_method,
 | 
| +                            self.calling_format.build_host(self.server_name(),
 | 
| +                                                           bucket_name))
 | 
| +
 | 
| +        return {"action": url, "fields": fields}
 | 
| +
 | 
| +    def generate_url(self, expires_in, method, bucket='', key='', headers=None,
 | 
| +                     query_auth=True, force_http=False, response_headers=None,
 | 
| +                     expires_in_absolute=False, version_id=None):
 | 
| +        headers = headers or {}
 | 
| +        if expires_in_absolute:
 | 
| +            expires = int(expires_in)
 | 
| +        else:
 | 
| +            expires = int(time.time() + expires_in)
 | 
| +        auth_path = self.calling_format.build_auth_path(bucket, key)
 | 
| +        auth_path = self.get_path(auth_path)
 | 
| +        # optional version_id and response_headers need to be added to
 | 
| +        # the query param list.
 | 
| +        extra_qp = []
 | 
| +        if version_id is not None:
 | 
| +            extra_qp.append("versionId=%s" % version_id)
 | 
| +        if response_headers:
 | 
| +            for k, v in response_headers.items():
 | 
| +                extra_qp.append("%s=%s" % (k, urllib.quote(v)))
 | 
| +        if self.provider.security_token:
 | 
| +            headers['x-amz-security-token'] = self.provider.security_token
 | 
| +        if extra_qp:
 | 
| +            delimiter = '?' if '?' not in auth_path else '&'
 | 
| +            auth_path += delimiter + '&'.join(extra_qp)
 | 
| +        c_string = boto.utils.canonical_string(method, auth_path, headers,
 | 
| +                                               expires, self.provider)
 | 
| +        b64_hmac = self._auth_handler.sign_string(c_string)
 | 
| +        encoded_canonical = urllib.quote(b64_hmac, safe='')
 | 
| +        self.calling_format.build_path_base(bucket, key)
 | 
| +        if query_auth:
 | 
| +            query_part = '?' + self.QueryString % (encoded_canonical, expires,
 | 
| +                                                   self.aws_access_key_id)
 | 
| +        else:
 | 
| +            query_part = ''
 | 
| +        if headers:
 | 
| +            hdr_prefix = self.provider.header_prefix
 | 
| +            for k, v in headers.items():
 | 
| +                if k.startswith(hdr_prefix):
 | 
| +                    # headers used for sig generation must be
 | 
| +                    # included in the url also.
 | 
| +                    extra_qp.append("%s=%s" % (k, urllib.quote(v)))
 | 
| +        if extra_qp:
 | 
| +            delimiter = '?' if not query_part else '&'
 | 
| +            query_part += delimiter + '&'.join(extra_qp)
 | 
| +        if force_http:
 | 
| +            protocol = 'http'
 | 
| +            port = 80
 | 
| +        else:
 | 
| +            protocol = self.protocol
 | 
| +            port = self.port
 | 
| +        return self.calling_format.build_url_base(self, protocol,
 | 
| +                                                  self.server_name(port),
 | 
| +                                                  bucket, key) + query_part
 | 
| +
 | 
| +    def get_all_buckets(self, headers=None):
 | 
| +        response = self.make_request('GET', headers=headers)
 | 
| +        body = response.read()
 | 
| +        if response.status > 300:
 | 
| +            raise self.provider.storage_response_error(
 | 
| +                response.status, response.reason, body)
 | 
| +        rs = ResultSet([('Bucket', self.bucket_class)])
 | 
| +        h = handler.XmlHandler(rs, self)
 | 
| +        xml.sax.parseString(body, h)
 | 
| +        return rs
 | 
| +
 | 
| +    def get_canonical_user_id(self, headers=None):
 | 
| +        """
 | 
| +        Convenience method that returns the "CanonicalUserID" of the
 | 
| +        user who's credentials are associated with the connection.
 | 
| +        The only way to get this value is to do a GET request on the
 | 
| +        service which returns all buckets associated with the account.
 | 
| +        As part of that response, the canonical userid is returned.
 | 
| +        This method simply does all of that and then returns just the
 | 
| +        user id.
 | 
| +
 | 
| +        :rtype: string
 | 
| +        :return: A string containing the canonical user id.
 | 
| +        """
 | 
| +        rs = self.get_all_buckets(headers=headers)
 | 
| +        return rs.owner.id
 | 
| +
 | 
| +    def get_bucket(self, bucket_name, validate=True, headers=None):
 | 
| +        """
 | 
| +        Retrieves a bucket by name.
 | 
| +
 | 
| +        If the bucket does not exist, an ``S3ResponseError`` will be raised. If
 | 
| +        you are unsure if the bucket exists or not, you can use the
 | 
| +        ``S3Connection.lookup`` method, which will either return a valid bucket
 | 
| +        or ``None``.
 | 
| +
 | 
| +        :type bucket_name: string
 | 
| +        :param bucket_name: The name of the bucket
 | 
| +
 | 
| +        :type headers: dict
 | 
| +        :param headers: Additional headers to pass along with the request to
 | 
| +            AWS.
 | 
| +
 | 
| +        :type validate: boolean
 | 
| +        :param validate: If ``True``, it will try to fetch all keys within the
 | 
| +            given bucket. (Default: ``True``)
 | 
| +        """
 | 
| +        bucket = self.bucket_class(self, bucket_name)
 | 
| +        if validate:
 | 
| +            bucket.get_all_keys(headers, maxkeys=0)
 | 
| +        return bucket
 | 
| +
 | 
| +    def lookup(self, bucket_name, validate=True, headers=None):
 | 
| +        """
 | 
| +        Attempts to get a bucket from S3.
 | 
| +
 | 
| +        Works identically to ``S3Connection.get_bucket``, save for that it
 | 
| +        will return ``None`` if the bucket does not exist instead of throwing
 | 
| +        an exception.
 | 
| +
 | 
| +        :type bucket_name: string
 | 
| +        :param bucket_name: The name of the bucket
 | 
| +
 | 
| +        :type headers: dict
 | 
| +        :param headers: Additional headers to pass along with the request to
 | 
| +            AWS.
 | 
| +
 | 
| +        :type validate: boolean
 | 
| +        :param validate: If ``True``, it will try to fetch all keys within the
 | 
| +            given bucket. (Default: ``True``)
 | 
| +        """
 | 
| +        try:
 | 
| +            bucket = self.get_bucket(bucket_name, validate, headers=headers)
 | 
| +        except:
 | 
| +            bucket = None
 | 
| +        return bucket
 | 
| +
 | 
| +    def create_bucket(self, bucket_name, headers=None,
 | 
| +                      location=Location.DEFAULT, policy=None):
 | 
| +        """
 | 
| +        Creates a new located bucket. By default it's in the USA. You can pass
 | 
| +        Location.EU to create an European bucket.
 | 
| +
 | 
| +        :type bucket_name: string
 | 
| +        :param bucket_name: The name of the new bucket
 | 
| +
 | 
| +        :type headers: dict
 | 
| +        :param headers: Additional headers to pass along with the request to AWS.
 | 
| +
 | 
| +        :type location: str
 | 
| +        :param location: The location of the new bucket.  You can use one of the
 | 
| +            constants in :class:`boto.s3.connection.Location` (e.g. Location.EU,
 | 
| +            Location.USWest, etc.).
 | 
| +
 | 
| +        :type policy: :class:`boto.s3.acl.CannedACLStrings`
 | 
| +        :param policy: A canned ACL policy that will be applied to the
 | 
| +            new key in S3.
 | 
| +
 | 
| +        """
 | 
| +        check_lowercase_bucketname(bucket_name)
 | 
| +
 | 
| +        if policy:
 | 
| +            if headers:
 | 
| +                headers[self.provider.acl_header] = policy
 | 
| +            else:
 | 
| +                headers = {self.provider.acl_header: policy}
 | 
| +        if location == Location.DEFAULT:
 | 
| +            data = ''
 | 
| +        else:
 | 
| +            data = '<CreateBucketConfiguration><LocationConstraint>' + \
 | 
| +                    location + '</LocationConstraint></CreateBucketConfiguration>'
 | 
| +        response = self.make_request('PUT', bucket_name, headers=headers,
 | 
| +                data=data)
 | 
| +        body = response.read()
 | 
| +        if response.status == 409:
 | 
| +            raise self.provider.storage_create_error(
 | 
| +                response.status, response.reason, body)
 | 
| +        if response.status == 200:
 | 
| +            return self.bucket_class(self, bucket_name)
 | 
| +        else:
 | 
| +            raise self.provider.storage_response_error(
 | 
| +                response.status, response.reason, body)
 | 
| +
 | 
| +    def delete_bucket(self, bucket, headers=None):
 | 
| +        """
 | 
| +        Removes an S3 bucket.
 | 
| +
 | 
| +        In order to remove the bucket, it must first be empty. If the bucket is
 | 
| +        not empty, an ``S3ResponseError`` will be raised.
 | 
| +
 | 
| +        :type bucket_name: string
 | 
| +        :param bucket_name: The name of the bucket
 | 
| +
 | 
| +        :type headers: dict
 | 
| +        :param headers: Additional headers to pass along with the request to
 | 
| +            AWS.
 | 
| +        """
 | 
| +        response = self.make_request('DELETE', bucket, headers=headers)
 | 
| +        body = response.read()
 | 
| +        if response.status != 204:
 | 
| +            raise self.provider.storage_response_error(
 | 
| +                response.status, response.reason, body)
 | 
| +
 | 
| +    def make_request(self, method, bucket='', key='', headers=None, data='',
 | 
| +            query_args=None, sender=None, override_num_retries=None):
 | 
| +        if isinstance(bucket, self.bucket_class):
 | 
| +            bucket = bucket.name
 | 
| +        if isinstance(key, Key):
 | 
| +            key = key.name
 | 
| +        path = self.calling_format.build_path_base(bucket, key)
 | 
| +        boto.log.debug('path=%s' % path)
 | 
| +        auth_path = self.calling_format.build_auth_path(bucket, key)
 | 
| +        boto.log.debug('auth_path=%s' % auth_path)
 | 
| +        host = self.calling_format.build_host(self.server_name(), bucket)
 | 
| +        if query_args:
 | 
| +            path += '?' + query_args
 | 
| +            boto.log.debug('path=%s' % path)
 | 
| +            auth_path += '?' + query_args
 | 
| +            boto.log.debug('auth_path=%s' % auth_path)
 | 
| +        return AWSAuthConnection.make_request(self, method, path, headers,
 | 
| +                data, host, auth_path, sender,
 | 
| +                override_num_retries=override_num_retries)
 | 
| 
 |