U
    W+dg                     @   s,  d dl Zd dlZd dlmZmZ d dlZd dlmZ d dl	Z
d dlmZ d dl
mZ d dlmZ d dlmZ d dlmZ d d	lmZmZ d
d Zdd ZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!G dd deZ"dS )     N)sixurllib)detect_potential_s3sigv4)AWSAuthConnection)handler)Bucket)Key)	ResultSet)BotoClientErrorS3ResponseErrorc                 C   s   | d   stddS )aJ  
    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
    azuBucket names cannot contain upper-case characters when using either the sub-domain or virtual hosting calling format.T)islowerr
   )n r   6/tmp/pip-unpacked-wheel-dlxw5sjy/boto/s3/connection.pycheck_lowercase_bucketname(   s    r   c                    s    fdd}|S )Nc                     s"   t | dkrt| d r | |S )N      )lenr   )argskwargsfr   r   wrapperB   s    z(assert_case_insensitive.<locals>.wrapperr   )r   r   r   r   r   assert_case_insensitiveA   s    r   c                   @   s:   e Zd Zdd ZdddZdd Zddd	Zdd
dZdS )_CallingFormatc                 C   s   dS N r   selfserverbucketr   r   r   get_bucket_serverK   s    z _CallingFormat.get_bucket_serverr   c                 C   s2   d| }||  ||7 }||| ||7 }|S )Nz%s://
build_hostget_pathbuild_path_baser   
connectionprotocolr    r!   keyZurl_baser   r   r   build_url_baseN   s    z_CallingFormat.build_url_basec                 C   s   |dkr|S |  ||S d S r   )r"   r   r   r   r   r$   T   s    z_CallingFormat.build_hostc                 C   s4   t j|}d}|dkr d| }|dtj|  S )Nr   //%sbotoutilsZget_utf8_valuer   parsequote)r   r!   r*   pathr   r   r   build_auth_pathZ   s
    z_CallingFormat.build_auth_pathc                 C   s   t j|}dtj| S )Nr-   r.   )r   r!   r*   r   r   r   r&   a   s    z_CallingFormat.build_path_baseN)r   )r   )r   )__name__
__module____qualname__r"   r+   r$   r4   r&   r   r   r   r   r   I   s
   

r   c                   @   s   e Zd Zedd ZdS )SubdomainCallingFormatc                 C   s   d||f S )Nz%s.%sr   r   r   r   r   r"   h   s    z(SubdomainCallingFormat.get_bucket_serverNr5   r6   r7   r   r"   r   r   r   r   r8   f   s   r8   c                   @   s   e Zd Zedd ZdS )VHostCallingFormatc                 C   s   |S Nr   r   r   r   r   r"   o   s    z$VHostCallingFormat.get_bucket_serverNr9   r   r   r   r   r:   m   s   r:   c                   @   s   e Zd Zdd ZdddZdS )OrdinaryCallingFormatc                 C   s   |S r;   r   r   r   r   r   r"   v   s    z'OrdinaryCallingFormat.get_bucket_serverr   c                 C   s0   t j|}d}|r |d| 7 }|tj| S )Nr,   z%s/r.   )r   r!   r*   Z	path_baser   r   r   r&   y   s
    z%OrdinaryCallingFormat.build_path_baseN)r   )r5   r6   r7   r"   r&   r   r   r   r   r<   t   s   r<   c                   @   s   e Zd ZdddZdS )(ProtocolIndependentOrdinaryCallingFormatr   c                 C   s.   d}||  ||7 }||| ||7 }|S )Nz//r#   r'   r   r   r   r+      s    z7ProtocolIndependentOrdinaryCallingFormat.build_url_baseN)r   )r5   r6   r7   r+   r   r   r   r   r=      s   r=   c                   @   s4   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdS )Locationr   EUzeu-central-1z	us-west-1z	us-west-2z	sa-east-1zap-northeast-1zap-southeast-1zap-southeast-2z
cn-north-1N)r5   r6   r7   DEFAULTr?   Z
EUCentral1ZUSWestZUSWest2ZSAEastZAPNortheastZAPSoutheastZAPSoutheast2ZCNNorth1r   r   r   r   r>      s   r>   c                   @   s   e Zd ZdS )NoHostProvidedNr5   r6   r7   r   r   r   r   rA      s   rA   c                   @   s   e Zd ZdS )HostRequiredErrorNrB   r   r   r   r   rC      s   rC   c                       s  e Zd ZdZejdddZdZdddddddde	dded	d
e
dddddf fdd	Zedd Zdd Zdd Zdd Zdd Zd2ddZd3ddZd4d d!Zd5d"d#Zd6d$d%Zd7d&d'Zd8d(d)Zd9d*d+Zdejdfd,d-Zd:d.d/Zd; fd0d1	Z  ZS )<S3Connectionzs3.amazonaws.coms3calling_formatz)boto.s3.connection.SubdomainCallingFormatz)Signature=%s&Expires=%d&AWSAccessKeyId=%sNTr   r,   ZawsFc                    s   d}|	t kr,tjdd}	|	d kr,| j}	d}t|tjrFtj	| }|| _
|| _|| _tt| j|	|||||||||
|||||||d |rd|  krtdd S )NFrE   hostT)debughttps_connection_factoryr3   providersecurity_tokensuppress_consec_slashesvalidate_certsprofile_name
hmac-v4-s3z6When using SigV4, you must specify a 'host' parameter.)rA   r/   configgetDefaultHost
isinstancer   string_typesr0   
find_classrF   bucket_classanonsuperrD   __init___required_auth_capabilityrC   )r   aws_access_key_idZaws_secret_access_keyZ	is_secureportproxyZ
proxy_portZ
proxy_userZ
proxy_passrG   rH   rI   rF   r3   rJ   rV   rK   rL   rW   rM   rN   Zno_host_provided	__class__r   r   rY      sD              	zS3Connection.__init__c                 C   s   | j rdgS dgS d S )NrW   rE   )rW   )r   r   r   r   rZ      s    z&S3Connection._required_auth_capabilityc                 c   s   |   D ]
}|V  qd S r;   )get_all_buckets)r   r!   r   r   r   __iter__   s    zS3Connection.__iter__c                 C   s   |  |d k	S r;   )lookup)r   bucket_namer   r   r   __contains__   s    zS3Connection.__contains__c                 C   s
   || _ dS )aX  
        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
        N)rV   )r   rV   r   r   r   set_bucket_class   s    	zS3Connection.set_bucket_classc                 C   s2   t |tjstddttjj|d|f S )zX
        Taken from the AWS book Python examples and modified for use with boto
        z;Policy document must include a valid expiration Time objectz({"expiration": "%s",
"conditions": [%s]},)	rS   timestruct_timeAssertionErrorstrftimer/   r0   ZISO8601join)r   Zexpiration_time
conditionsr   r   r   build_post_policy   s    zS3Connection.build_post_policyp  httpSTANDARDc                 C   s  |dkrg }|	dkrg }	t tt   | }|	d|  |drd|	d|dtd    n|	d|  |r|	d|  |d|d |r|	d	|  |d
|d |r|	d|  | jjr|d| jjd |	d| jj  |
r|d|
d |	d|
  |r>|d|d |	d|  | ||	}t	
|}|d|d |d| jd | j|}|d|d |d|d d|| j|  |f }||dS )a  
        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


        Nz{"bucket": "%s"}z${filename}z["starts-with", "$key", "%s"]z{"key": "%s"}z{"acl": "%s"}acl)namevaluez!{"success_action_redirect": "%s"}success_action_redirectz["content-length-range", 0, %i]x-amz-security-tokenz{"x-amz-security-token": "%s"}zx-amz-storage-classz{"x-amz-storage-class": "%s"}zx-amz-server-side-encryptionz&{"x-amz-server-side-encryption": "%s"}policyZAWSAccessKeyId	signaturer*   z%s://%s/)actionfields)rg   gmtimeintappendendswithr   rJ   rK   rm   base64	b64encoder[   _auth_handlersign_stringrF   r$   server_name)r   rc   r*   
expires_inrq   rt   Zmax_content_lengthZhttp_methodry   rl   Zstorage_classZserver_side_encryptionZ
expirationrv   Z
policy_b64rw   urlr   r   r   build_post_form_args   s^    :

z!S3Connection.build_post_form_argsr   c
                 C   s   | j ||}
| j ||}| j |  |}|drD|d d }i }|d k	rX||d< |d k	rj|| | j||
||||d}| jj	|||	dS )Nz:443Z	VersionId)headersrG   params)iso_date)
rF   r&   r4   r$   r   r}   updateZbuild_base_http_requestr   Zpresign)r   r   methodr!   r*   r   
force_httpresponse_headers
version_idr   r3   	auth_pathrG   r   http_requestr   r   r   generate_url_sigv4e  s$    


 
zS3Connection.generate_url_sigv4c              
   C   s  | j jd dkr.|r.| j||||||||
dS |p4i }|	rDt|}ntt | }| j||}| |}g }|
d k	r|d|
  |r|	 D ]"\}}|d|t
j|f  q| jjr| jj|d< |rd|krdnd}||d| 7 }| j|| |rV| jsVtj||||| j}| j |}t
jj|d	d
}d| j||| jf  }nd	}|r| jj}|	 D ]0\}}||rp|d|t
j|f  qp|r|sdnd}||d| 7 }|rd}d}n| j}| j}| j| || |||| S )Nr   rO   )r!   r*   r   r   r   r   zversionId=%sz%s=%sru   ?&r   )safero   P   )r   Z
capabilityr   r{   rg   rF   r4   r%   r|   itemsr   r1   r2   rJ   rK   rk   r&   rW   r/   r0   Zcanonical_stringr   QueryStringr[   Zheader_prefix
startswithr)   r\   r+   r   )r   r   r   r!   r*   r   Z
query_authr   r   Zexpires_in_absoluter   expiresr   Zextra_qpkv	delimiterZc_stringZb64_hmacZencoded_canonicalZ
query_partZ
hdr_prefixr)   r\   r   r   r   generate_url  sr    
   

 


 zS3Connection.generate_urlc                 C   sv   | j d|d}| }|jdkr4| j|j|j|td| jfg}t	|| }t
|tsd|d}tj|| |S )NGETr   i,  r   zutf-8)make_requestreadstatusrJ   storage_response_errorreasonr	   rV   r   Z
XmlHandlerrS   bytesencodexmlsaxparseString)r   r   responsebodyrshr   r   r   r`     s    
  

zS3Connection.get_all_bucketsc                 C   s   | j |d}|jjS )a  
        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.
        r   )r`   ownerid)r   r   r   r   r   r   get_canonical_user_id  s    z"S3Connection.get_canonical_user_idc                 C   s"   |r| j ||dS | | |S dS )a  
        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``.

        If ``validate=False`` is passed, no request is made to the service (no
        charge/communication delay). This is only safe to do if you are **sure**
        the bucket exists.

        If the default ``validate=True`` is passed, a request is made to the
        service to ensure the bucket exists. Prior to Boto v2.25.0, this fetched
        a list of keys (but with a max limit set to ``0``, always returning an empty
        list) in the bucket (& included better error messages), at an
        increased expense. As of Boto v2.25.0, this now performs a HEAD request
        (less expensive but worse error messages).

        If you were relying on parsing the error message before, you should call
        something like::

            bucket = conn.get_bucket('<bucket_name>', validate=False)
            bucket.get_all_keys(maxkeys=0)

        :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 verify the bucket exists
            on the service-side. (Default: ``True``)
        r   N)head_bucketrV   )r   rc   validater   r   r   r   
get_bucket  s    %zS3Connection.get_bucketc                 C   s   | j d||d}| }|jdkr.| | |S |jdkr^| j|j|j|}d|_d|_|nD|jdkr| j|j|j|}d|_d	|_|n| j|j|j|d
S )a|  
        Determines if a bucket exists by name.

        If the bucket does not exist, 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.

        :returns: A <Bucket> object
        HEADr      i  ZAccessDeniedzAccess Deniedi  ZNoSuchBucketz#The specified bucket does not existN)	r   r   r   rV   rJ   r   r   Z
error_codeerror_message)r   rc   r   r   r   errr   r   r   r     s6    


  zS3Connection.head_bucketc                 C   s*   z| j |||d}W n   d}Y nX |S )aR  
        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``)
        r   N)r   )r   rc   r   r   r!   r   r   r   rb   .  s
    
zS3Connection.lookupc                 C   s   t | |r*|r||| jj< n| jj|i}|tjkr:d}nd| d }| jd|||d}| }|jdkr~| j|j|j	||jdkr| 
| |S | j|j|j	|dS )	a  
        Creates a new located bucket. By default it's in the USA. You can pass
        Location.EU to create a European bucket (S3) or European Union bucket
        (GCS).

        :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.

        r   z/<CreateBucketConfiguration><LocationConstraint>z1</LocationConstraint></CreateBucketConfiguration>PUT)r   datai  r   N)r   rJ   Z
acl_headerr>   r@   r   r   r   Zstorage_create_errorr   rV   r   )r   rc   r   locationrv   r   r   r   r   r   r   create_bucketG  s:    


  
  zS3Connection.create_bucketc                 C   s:   | j d||d}| }|jdkr6| j|j|j|dS )a  
        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.
        DELETEr      N)r   r   r   rJ   r   r   )r   r!   r   r   r   r   r   r   delete_bucketv  s    
  zS3Connection.delete_bucketc
                    s   t || jr|j}t |tr"|j}| j||}
tjd|
  | j	||}tjd|  | j
|  |}|r|
d| 7 }
tjd|
  |d| 7 }tjd|  tt| j||
|||||||	d	S )Nzpath=%szauth_path=%sr   )override_num_retriesretry_handler)rS   rV   rr   r   rF   r&   r/   logrH   r4   r$   r   rX   rD   r   )r   r   r!   r*   r   r   Z
query_argsZsenderr   r   r3   r   rG   r^   r   r   r     s2    

     zS3Connection.make_request)	rn   NNNro   NNrp   N)r   r   NFNNN)r   r   NTFNFN)N)N)TN)N)TN)N)r   r   Nr   NNNN) r5   r6   r7   rR   r/   rP   rQ   ZDefaultCallingFormatr   rA   r   rY   r   rZ   ra   rd   re   rm   r   r   r   r`   r   r   r   rb   r>   r@   r   r   r   __classcell__r   r   r^   r   rD      s              #
            
u        
         
;


*
-
 
/
       rD   )#Zxml.saxr   r~   Zboto.compatr   r   rg   Z	boto.authr   Z
boto.utilsr/   Zboto.connectionr   r   Zboto.s3.bucketr   Zboto.s3.keyr   Zboto.resultsetr	   Zboto.exceptionr
   r   r   r   objectr   r8   r:   r<   r=   r>   rA   rC   rD   r   r   r   r   <module>   s,   	