U
    P’“e8f  ã                   @   sN  d 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mZ ddlmZ dd	lmZ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 zddlZdZddlmZ W n ek
rÜ   Y nX g Z G dd„ deƒZ!G dd„ de!ƒZ"G dd„ de!ƒZ#e"e#e"dœZ$ej% &d¡s<e 'ddd¡Z(ndZ(e$ &e(¡Z)dS )aH  
UrlRequest
==========

.. versionadded:: 1.0.8

You can use the :class:`UrlRequest` to make asynchronous requests on the
web and get the result when the request is completed. The spirit is the
same as the XHR object in Javascript.

The content is also decoded if the Content-Type is
application/json and the result automatically passed through json.loads.


The syntax to create a request::

    from kivy.network.urlrequest import UrlRequest
    req = UrlRequest(url, on_success, on_redirect, on_failure, on_error,
                     on_progress, req_body, req_headers, chunk_size,
                     timeout, method, decode, debug, file_path, ca_file,
                     verify)


Only the first argument is mandatory: the rest are optional.
By default, a "GET" request will be sent. If the :attr:`UrlRequest.req_body` is
not None, a "POST" request will be sent. It's up to you to adjust
:attr:`UrlRequest.req_headers` to suit your requirements and the response
to the request will be accessible as the parameter called "result" on
the callback function of the on_success event.


Example of fetching JSON::

    def got_json(req, result):
        for key, value in req.resp_headers.items():
            print('{}: {}'.format(key, value))

    req = UrlRequest('https://httpbin.org/headers', got_json)

Example of Posting data (adapted from httplib example)::

    import urllib

    def bug_posted(req, result):
        print('Our bug is posted!')
        print(result)

    params = urllib.urlencode({'@number': 12524, '@type': 'issue',
        '@action': 'show'})
    headers = {'Content-type': 'application/x-www-form-urlencoded',
              'Accept': 'text/plain'}
    req = UrlRequest('bugs.python.org', on_success=bug_posted, req_body=params,
            req_headers=headers)

If you want a synchronous request, you can call the wait() method.

é    N)Ú	b64encode)Údeque)ÚHTTPConnection)Úloads)ÚEventÚThread)Úsleep)ÚurlparseÚ
urlunparse)ÚClock)ÚConfig)ÚLogger)Úplatform)Ú
WeakMethod)ÚHTTPSConnectionc                       sœ   e Zd ZdZd!‡ fdd„	Zdd	„ Zd
d„ Zdd„ Zdd„ Ze	dd„ ƒZ
e	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZe	dd„ ƒZd"dd„Zdd „ Z‡  ZS )#ÚUrlRequestBaseaÜ  A UrlRequest. See module documentation for usage.

    .. versionchanged:: 1.5.1
        Add `debug` parameter

    .. versionchanged:: 1.0.10
        Add `method` parameter

    .. versionchanged:: 1.8.0

        Parameter `decode` added.
        Parameter `file_path` added.
        Parameter `on_redirect` added.
        Parameter `on_failure` added.

    .. versionchanged:: 1.9.1

        Parameter `ca_file` added.
        Parameter `verify` added.

    .. versionchanged:: 1.10.0

        Parameters `proxy_host`, `proxy_port` and `proxy_headers` added.

    .. versionchanged:: 1.11.0

        Parameters `on_cancel` added.

    .. versionchanged:: 2.2.0

        Parameters `on_finish` added.
        Parameters `auth` added.

    :Parameters:
        `url`: str
            Complete url string to call.
        `on_success`: callback(request, result)
            Callback function to call when the result has been fetched.
        `on_redirect`: callback(request, result)
            Callback function to call if the server returns a Redirect.
        `on_failure`: callback(request, result)
            Callback function to call if the server returns a Client or
            Server Error.
        `on_error`: callback(request, error)
            Callback function to call if an error occurs.
        `on_progress`: callback(request, current_size, total_size)
            Callback function that will be called to report progression of the
            download. `total_size` might be -1 if no Content-Length has been
            reported in the http response.
            This callback will be called after each `chunk_size` is read.
        `on_cancel`: callback(request)
            Callback function to call if user requested to cancel the download
            operation via the .cancel() method.
        `on_finish`: callback(request)
            Additional callback function to call if request is done.
        `req_body`: str, defaults to None
            Data to sent in the request. If it's not None, a POST will be done
            instead of a GET.
        `req_headers`: dict, defaults to None
            Custom headers to add to the request.
        `chunk_size`: int, defaults to 8192
            Size of each chunk to read, used only when `on_progress` callback
            has been set. If you decrease it too much, a lot of on_progress
            callbacks will be fired and will slow down your download. If you
            want to have the maximum download speed, increase the chunk_size
            or don't use ``on_progress``.
        `timeout`: int, defaults to None
            If set, blocking operations will timeout after this many seconds.
        `method`: str, defaults to 'GET' (or 'POST' if ``body`` is specified)
            The HTTP method to use.
        `decode`: bool, defaults to True
            If False, skip decoding of the response.
        `debug`: bool, defaults to False
            If True, it will use the Logger.debug to print information
            about url access/progression/errors.
        `file_path`: str, defaults to None
            If set, the result of the UrlRequest will be written to this path
            instead of in memory.
        `ca_file`: str, defaults to None
            Indicates a SSL CA certificate file path to validate HTTPS
            certificates against
        `verify`: bool, defaults to True
            If False, disables SSL CA certificate verification
        `proxy_host`: str, defaults to None
            If set, the proxy host to use for this connection.
        `proxy_port`: int, defaults to None
            If set, and `proxy_host` is also set, the port to use for
            connecting to the proxy server.
        `proxy_headers`: dict, defaults to None
            If set, and `proxy_host` is also set, the headers to send to the
            proxy server in the ``CONNECT`` request.
        `auth`: HTTPBasicAuth, defaults to None
            If set, request will use basicauth to authenticate.
            Only used in "Requests" implementation
    Né    TFc                    sx  t ƒ  ¡  tƒ | _t | jd¡| _d| _|r4t	|ƒnd | _
|rFt	|ƒnd | _|rXt	|ƒnd | _|rjt	|ƒnd | _|r|t	|ƒnd | _|rŽt	|ƒnd | _|r t	|ƒnd | _|| _|| _|| _d | _d | _d| _d | _d | _d| _|	| _|
| _|| _|| _|| _|| _|| _ t!ƒ | _"|| _#|| _$|| _%|| _&t'dkrJdd l(}|pD| )¡ | _*n|| _*|| _+|| _,|| _-t. /| ¡ |  0¡  d S )Nr   TFéÿÿÿÿ)ZandroidZios)1ÚsuperÚ__init__r   Ú_queuer   Zcreate_triggerÚ_dispatch_resultÚ_trigger_resultÚdaemonr   Ú
on_successÚon_redirectÚ
on_failureÚon_errorÚon_progressÚ	on_cancelÚ	on_finishÚdecodeÚ	file_pathÚ_debugÚ_resultÚ_errorÚ_is_finishedÚ_resp_statusÚ_resp_headersZ_resp_lengthÚ_chunk_sizeÚ_timeoutÚ_methodÚverifyÚ_proxy_hostÚ_proxy_portÚ_proxy_headersr   Ú_cancel_eventÚ_user_agentÚ_cookiesÚ_requested_urlÚ_authr   ÚcertifiÚwhereÚca_fileÚurlÚreq_bodyÚreq_headersÚ
g_requestsÚappendÚstart)Úselfr8   r   r   r   r   r   r9   r:   Ú
chunk_sizeÚtimeoutÚmethodr!   Údebugr"   r7   r,   Z
proxy_hostZ
proxy_portÚproxy_headersÚ
user_agentr   r    ÚcookiesÚauthr5   ©Ú	__class__© ú;/tmp/pip-unpacked-wheel-xzebddm3/kivy/network/urlrequest.pyr   »   sR    	


zUrlRequestBase.__init__c              
   C   s:  | j j}| j}| j}| jpi }| j}| j}|r<| d|¡ n0t 	d¡rldt 
d¡krlt dd¡}| d|¡ |r|| d|¡ z*|  ||||¡\}}	| jr¤|  ||	¡}W n0 tk
rÖ }
 z|dd |
fƒ W 5 d }
~
X Y n$X | j ¡ sò|d|	|fƒ n|dƒ |  ¡  t| j ƒr"tdƒ |  ¡  q| tkr6t | ¡ d S )	Nz
User-AgentÚnetworkÚ	useragentÚCookieÚerrorÚsuccess)ÚkilledNNgš™™™™™¹?)r   Ú
appendleftr8   r9   r:   r1   r2   Ú
setdefaultr   Úhas_sectionÚitemsÚgetÚ
_fetch_urlr!   Údecode_resultÚ	Exceptionr0   Úis_setr   Úlenr   r;   Úremove)r>   Úqr8   r9   r:   rD   rE   rL   ÚresultÚrespÚerI   rI   rJ   Úrunù   s>    
ÿþ 

zUrlRequestBase.runc              
   C   sd  | j }| j}| jd k	}| j}| jrdt d t| ƒ|¡¡ t d t| ƒ|¡¡ t d t| ƒ|¡¡ |  	||¡\}	}
|s‚|d k	r|  
|
¡}|r¢|d|
d|ffƒ |d k	rÞt|dƒ"}| j|
||||||d\}}W 5 Q R X n|  |
|||||¡\}}|rR|d|
||ffƒ |ƒ  n<|  |
¡}zt|tƒr8| d¡}W n tk
rP   Y nX |  |	¡ ||
fS )	NzUrlRequest: {0} Fetch url <{1}>zUrlRequest: {0} - body: {1}zUrlRequest: {0} - headers: {1}Úprogressr   Úwb)Úfdúutf-8)r   r)   r   r"   r#   r   rB   ÚformatÚidÚcall_requestÚget_total_sizeÚopenÚ
get_chunksÚget_responseÚ
isinstanceÚbytesr!   ÚUnicodeDecodeErrorÚclose_connection)r>   r8   ÚbodyÚheadersr\   Útriggerr?   Úreport_progressr"   Úreqr^   Ú
total_sizerc   Úbytes_so_farr]   rI   rI   rJ   rV   '  sh    
 ÿ ÿ ÿ
     þ     ÿ

zUrlRequestBase._fetch_urlc                 C   sd   |   |¡}|dk	r`| d¡d }|dkr`t|tƒr<| d¡}z
t|ƒW S  tk
r^   | Y S X |S )z|Decode the result fetched from url according to his Content-Type.
        Currently supports only application/json.
        Nú;r   zapplication/jsonrd   )Úget_content_typeÚsplitrl   rm   r!   r   rX   )r>   r]   r^   Úcontent_typeÚctrI   rI   rJ   rW   _  s    




zUrlRequestBase.decode_resultc                 C   sä  z| j  ¡ \}}}W n tk
r*   Y d S X |ržd}g }|  |¡D ].\}}|dkrb|d |¡7 }qB| ||f¡ qB| d|d d… f¡ t|ƒ| _|  |¡| _	|dkrº|  |¡d }	|	dkr
| j
rÜt d t| ƒ|¡¡ d	| _|| _| jr¸|  ¡ }
|
r¸|
| |ƒ n®|	d
kr^| j
r0t d t| ƒ¡¡ d	| _|| _| jr¸|  ¡ }
|
r¸|
| |ƒ nZ|	dkrª| j
rŒt d t| ƒ|  |¡¡¡ d	| _|| _| jrª|  ¡ }
|
rª|
| |ƒ nð|dkr| j
rât d t| ƒ|¡¡ d	| _|| _| jrª|  ¡ }
|
rª|
| |ƒ nš|dkrd| j
r8t d t| ƒ|¡¡ | jrª|  ¡ }
|
rª|
| |d |d ƒ nF|dkr | j
r€t d¡ | jrª|  ¡ }
|
rª|
| ƒ n
dsªt‚|dkr | jr | j
rÊt d¡ |  ¡ }
|
r |
| ƒ q d S )NÚ z
Set-Cookiez{};r   rO   éd   )é   é   z2UrlRequest: {0} Download finished with {1} datalenTé   z"UrlRequest: {} Download redirected)é   é   z1UrlRequest: {} Download failed with http error {}rN   z$UrlRequest: {0} Download error <{1}>ra   z%UrlRequest: {0} Download progress {1}r   r~   rP   zUrlRequest: Cancelled by userzUrlRequest: Request is finished)r   ÚpopÚ
IndexErrorÚget_all_headersre   r<   Údictr(   Úget_status_coder'   r#   r   rB   rf   r&   r$   r   r   r   r%   r   r   r   ÚAssertionErrorr    )r>   Údtr]   r^   ÚdataZfinal_cookiesZparsed_headersÚkeyÚvalueZstatus_classÚfuncrI   rI   rJ   r   s  s¶    


 ÿÿ
ÿ
ýÿ
 ÿ
 ÿ




zUrlRequestBase._dispatch_resultc                 C   s   | j S )z^Return True if the request has finished, whether it's a
        success or a failure.
        )r&   ©r>   rI   rI   rJ   Úis_finishedß  s    zUrlRequestBase.is_finishedc                 C   s   | j S )znReturn the result of the request.
        This value is not determined until the request is finished.
        )r$   rŽ   rI   rI   rJ   r]   æ  s    zUrlRequestBase.resultc                 C   s   | j S )zIf the request has been completed, return a dictionary containing
        the headers of the response. Otherwise, it will return None.
        )r(   rŽ   rI   rI   rJ   Úresp_headersí  s    zUrlRequestBase.resp_headersc                 C   s   | j S )zjReturn the status code of the response if the request is complete,
        otherwise return None.
        )r'   rŽ   rI   rI   rJ   Úresp_statusô  s    zUrlRequestBase.resp_statusc                 C   s   | j S )znReturn the error of the request.
        This value is not determined until the request is completed.
        )r%   rŽ   rI   rI   rJ   rN   û  s    zUrlRequestBase.errorc                 C   s   | j S )zmReturn the size of a chunk, used only in "progress" mode (when
        on_progress callback is set.)
        )r)   rŽ   rI   rI   rJ   r?     s    zUrlRequestBase.chunk_sizeç      à?c                 C   s"   | j dkr|  |¡ t|ƒ q dS )a:  Wait for the request to finish (until :attr:`resp_status` is not
        None)

        .. note::
            This method is intended to be used in the main thread, and the
            callback will be dispatched from the same thread
            from which you're calling.

        .. versionadded:: 1.1.0
        N)r‘   r   r   )r>   ÚdelayrI   rI   rJ   Úwait	  s    

zUrlRequestBase.waitc                 C   s   | j  ¡  dS )zÈCancel the current request. It will be aborted, and the result
        will not be dispatched. Once cancelled, the callback on_cancel will
        be called.

        .. versionadded:: 1.11.0
        N)r0   ÚsetrŽ   rI   rI   rJ   Úcancel  s    zUrlRequestBase.cancel)NNNNNNNr   NNTFNNTNNNNNNNN)r’   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r`   rV   rW   r   Úpropertyr   r]   r   r‘   rN   r?   r”   r–   Ú__classcell__rI   rI   rG   rJ   r   Z   sV   a                                       ù>.8l






r   c                   @   s^   e Zd Zddd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ ZdS )ÚUrlRequestUrllibNc                 C   sn   d}d}	|  |¡}
|
sqf|r(| |
¡ n|	|
7 }	|t|
ƒ7 }|rX|d|||ffƒ |ƒ  | j ¡ rqfq||	fS ©Nr   ó    ra   )ÚreadÚwriterZ   r0   rY   ©r>   r^   r?   ru   rs   r\   rr   rc   rv   r]   ÚchunkrI   rI   rJ   rj   $  s    

zUrlRequestUrllib.get_chunksc                 C   s   |  ¡ S ©N)r    ©r>   r^   rI   rI   rJ   rk   A  s    zUrlRequestUrllib.get_responsec                 C   s,   zt | d¡ƒW S  tk
r&   Y dS X d S )Nzcontent-lengthr   )ÚintÚ	getheaderrX   r¥   rI   rI   rJ   rh   D  s    zUrlRequestUrllib.get_total_sizec                 C   s   |  dd ¡S ©NzContent-Type)r§   r¥   rI   rI   rJ   rx   J  s    z!UrlRequestUrllib.get_content_typec                 C   s   |j S r¤   )Ústatusr¥   rI   rI   rJ   r‡   M  s    z UrlRequestUrllib.get_status_codec                 C   s   |  ¡ S r¤   )Ú
getheadersr¥   rI   rI   rJ   r…   P  s    z UrlRequestUrllib.get_all_headersc                 C   s   |  ¡  d S r¤   )Úclose©r>   rt   rI   rI   rJ   ro   S  s    z!UrlRequestUrllib.close_connectionc                 C   sZ   t |ƒ}|j}|j}d }|jrN|jrNdd td |j|j¡ d¡ƒ d¡¡i}||||fS )NÚAuthorizationzBasic {}z{}:{}rd   )	r	   ÚhostnameÚportÚusernameÚpasswordre   r   Úencoder!   )r>   r8   ÚparseÚhostr¯   ÚuserpassrI   rI   rJ   Ú
_parse_urlV  s$     þýÿûÿ	zUrlRequestUrllib._parse_urlc                 C   s0   |dkrt S |dkr tdk	r tS td| ƒ‚dS )zÊReturn the Connection class for a particular scheme.
        This is an internal function that can be expanded to support custom
        schemes.

        Actual supported schemes: http, https.
        ÚhttpÚhttpsNzNo class for scheme %s)r   r   rX   )r>   ÚschemerI   rI   rJ   Ú_get_connection_for_schemei  s
    z+UrlRequestUrllib._get_connection_for_schemec                 C   sâ  | j }| j}| j}| j}|  |¡\}}}	}
|	r8|s8|	}n$|	r\|r\t|	 ¡ ƒd }|	| ||< |  |
j¡}|
j	}|
j
r‚|d|
j
 7 }|
jr–|d|
j 7 }|
jrª|d|
j 7 }i }|d k	r¾||d< |d k	röttdƒrö|
jdkrötj|d}tj|_||d	< |s2|
jdkr2ttdƒr2t ¡ }d
|_tj|_||d	< | jrt d t| ƒ| j| j¡¡ || j| jf|Ž}|
jdkr†| ||| j¡ nt|
ƒ}n|||f|Ž}| j}|d krÀ|d kr¼dnd}| ||||pÒi ¡ || ¡ fS )Nr   rw   ú?ú#r@   Úcreate_default_contextr¸   )ÚcafileÚcontextFz#UrlRequest: {0} - proxy via {1}:{2}ÚGETÚPOST) r*   r7   r,   r3   r¶   ÚlistÚkeysrº   r¹   ÚpathÚparamsÚqueryÚfragmentÚhasattrÚsslr½   ÚCERT_REQUIREDÚverify_modeÚcheck_hostnameÚ	CERT_NONEr-   r   rB   re   rf   r.   Ú
set_tunnelr/   r
   r+   ÚrequestÚgetresponse)r>   rp   rq   r@   r7   r,   r8   r´   r¯   rµ   r³   r‹   ÚclsrÄ   ÚargsÚctxrt   rA   rI   rI   rJ   rg   w  sd    ÿÿ  ÿ

zUrlRequestUrllib.call_request)N)r—   r˜   r™   rj   rk   rh   rx   r‡   r…   ro   r¶   rº   rg   rI   rI   rI   rJ   r   "  s    þ
r   c                   @   sN   e Zd Zddd„Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dd„ Z
dS )ÚUrlRequestRequestsNc                 C   sv   d}d}	|  |¡D ]Z}
|
s qn|r.| |
¡ n|	|
7 }	|t|
ƒ7 }|r^|d|||ffƒ |ƒ  | j ¡ r qnq||	fS rž   )Úiter_contentr¡   rZ   r0   rY   r¢   rI   rI   rJ   rj   ¼  s    
zUrlRequestRequests.get_chunksc                 C   s   |j S r¤   )Úcontentr¥   rI   rI   rJ   rk   Ø  s    zUrlRequestRequests.get_responsec                 C   s   t |j dd¡ƒS )NzContent-Lengthr   )r¦   rq   rU   r¥   rI   rI   rJ   rh   Û  s    z!UrlRequestRequests.get_total_sizec                 C   s   |j  dd ¡S r¨   )rq   rU   r¥   rI   rI   rJ   rx   Þ  s    z#UrlRequestRequests.get_content_typec                 C   s   |j S r¤   )Ústatus_coder¥   rI   rI   rJ   r‡   á  s    z"UrlRequestRequests.get_status_codec                 C   s
   |j  ¡ S r¤   )rq   rT   r¥   rI   rI   rJ   r…   ä  s    z"UrlRequestRequests.get_all_headersc                 C   s   d S r¤   rI   r¬   rI   rI   rJ   ro   ç  s    z#UrlRequestRequests.close_connectionc                 C   s†   | j }| j}| j}| j}| j}t}i }	| jd krB|d kr<dnd}
n
| j ¡ }
t||
ƒ}|rb||	d< ||f|||||dœ|	—Ž}d |fS )NrU   ÚpostrF   )rŠ   rq   r@   r,   Úcert)	r*   r7   r,   r3   r4   Úrequestsr+   ÚlowerÚgetattr)r>   rp   rq   r@   r7   r,   r8   rF   rt   ÚkwargsrA   Zreq_callÚresponserI   rI   rJ   rg   ê  s2    


ÿúù
zUrlRequestRequests.call_request)N)r—   r˜   r™   rj   rk   rh   rx   r‡   r…   ro   rg   rI   rI   rI   rJ   rÔ   º  s    þ
rÔ   )ÚdefaultrÚ   ÚurllibZKIVY_DOC_INCLUDErK   Úimplementationrß   )*rš   ÚosÚbase64r   Úcollectionsr   Úhttp.clientr   Újsonr   Ú	threadingr   r   Útimer   Úurllib.parser	   r
   rÚ   Z
kivy.clockr   Zkivy.configr   Zkivy.loggerr   Z
kivy.utilsr   Zkivy.weakmethodr   rÉ   r   ÚImportErrorr;   r   r   rÔ   Zimplementation_mapÚenvironrU   Z
getdefaultZprefered_implementationZ
UrlRequestrI   rI   rI   rJ   Ú<module>   sP   :   K Tý  ÿ