U
    lufT`                     @   s  d Z ddlZddlZddlZddlZddl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mZ ddlmZmZmZmZmZ ddlmZ dd	lmZmZmZmZmZ ddlZejrdd
lmZmZ e dZ!G dd deZ"G dd deZ#e$dkre%e" e  dS )z5Non-blocking HTTP client implementation using pycurl.    N)BytesIO)httputil)ioloop)utf8
native_str)HTTPRequestHTTPResponse	HTTPErrorAsyncHTTPClientmain)app_log)DictAnyCallableUnionOptional)DequeTupleztornado.curl_httpclientc                       s^  e Zd Zd.eeeeef  dd fddZdd fddZ	e
eegdf dd	d
dZeeeeddddZeddddZeeddddZddddZddddZddddZddddZd/ejee ee ddddZedd d!d"Zejdd#d$Zeje
eejdd%d&d'Zejeegdf edd(d)d*Zeedd+d,d-Z   Z!S )0CurlAsyncHTTPClient
   N)max_clientsdefaultsreturnc                    s   t  j|d t  _ jtj j  jtj j	  fddt
|D  _ jd d   _t  _i  _d  _t jd _ j  t } j|  j| d S )N)r   c                    s   g | ]}   qS  )_curl_create).0iselfr   ;/tmp/pip-unpacked-wheel-bmg6zs32/tornado/curl_httpclient.py
<listcomp>9   s     z2CurlAsyncHTTPClient.initialize.<locals>.<listcomp>  )super
initializepycurlZ	CurlMulti_multisetoptZM_TIMERFUNCTION_set_timeoutZM_SOCKETFUNCTION_handle_socketrange_curls
_free_listcollectionsdeque	_requests_fds_timeoutr   ZPeriodicCallback_handle_force_timeout_force_timeout_callbackstartCurl
add_handleremove_handle)r   r   r   Zdummy_curl_handle	__class__r   r   r#   1   s$    
 
zCurlAsyncHTTPClient.initialize)r   c                    sZ   | j   | jd k	r"| j| j | jD ]}|  q(| j  t   d | _ d | _d S N)	r2   stopr0   io_loopremove_timeoutr*   closer%   r"   r   curlr7   r   r   r=   S   s    





zCurlAsyncHTTPClient.close)requestcallbackr   c                 C   s.   | j ||| j f |   | d d S Nr   )r.   appendr;   time_process_queuer'   )r   r@   rA   r   r   r   
fetch_implb   s    zCurlAsyncHTTPClient.fetch_impl)eventfdmultidatar   c              	   C   s   t jtjjt jtjjt jtjjt j	tjjtjjB i}|t j
kr^|| jkr| j| | j|= n:|| }|| jkr|| j| | j|| j| || j|< dS )z_Called by libcurl when it wants to change the file descriptors
        it cares about.
        N)r$   Z	POLL_NONEr   IOLoopNONEZPOLL_INREADZPOLL_OUTWRITEZ
POLL_INOUTZPOLL_REMOVEr/   r;   Zremove_handleradd_handler_handle_events)r   rG   rH   rI   rJ   Z	event_mapZioloop_eventr   r   r   r(   i   s$        


	
z"CurlAsyncHTTPClient._handle_socket)msecsr   c                 C   s<   | j dk	r| j| j  | j| j |d  | j| _ dS )z(Called by libcurl to schedule a timeout.Ng     @@)r0   r;   r<   Zadd_timeoutrD   _handle_timeout)r   rQ   r   r   r   r'      s    
 z CurlAsyncHTTPClient._set_timeout)rH   eventsr   c              
   C   s   d}|t jj@ r|tjO }|t jj@ r0|tjO }z| j||\}}W n. tj	k
rt } z|j
d }W 5 d}~X Y nX |tjkr0qq0|   dS )zXCalled by IOLoop when there is activity on one of our
        file descriptors.
        r   N)r   rK   rM   r$   Z
CSELECT_INrN   ZCSELECT_OUTr%   socket_actionerrorargsE_CALL_MULTI_PERFORM_finish_pending_requests)r   rH   rS   actionretnum_handleser   r   r   rP      s    


z"CurlAsyncHTTPClient._handle_eventsc              
   C   s   d| _ z| jtjd\}}W n. tjk
rL } z|jd }W 5 d}~X Y nX |tjkrq\q|   | j	 }|dkr| 
| dS )z7Called by IOLoop when the requested timeout has passed.Nr   )r0   r%   rT   r$   ZSOCKET_TIMEOUTrU   rV   rW   rX   timeoutr'   )r   rZ   r[   r\   Znew_timeoutr   r   r   rR      s    

z#CurlAsyncHTTPClient._handle_timeoutc              
   C   s\   z| j  \}}W n. tjk
r@ } z|jd }W 5 d}~X Y nX |tjkr qPq |   dS )zpCalled by IOLoop periodically to ask libcurl to process any
        events it may have forgotten about.
        r   N)r%   Z
socket_allr$   rU   rV   rW   rX   )r   rZ   r[   r\   r   r   r   r1      s    
z)CurlAsyncHTTPClient._handle_force_timeoutc                 C   sZ   | j  \}}}|D ]}| | q|D ]\}}}| ||| q(|dkr qNq |   dS )zbProcess any requests that were completed by the last
        call to multi.socket_action.
        r   N)r%   Z	info_read_finishrE   )r   Znum_qZok_listZerr_listr?   Zerrnumerrmsgr   r   r   rX      s    z,CurlAsyncHTTPClient._finish_pending_requestsc              
   C   s   d}| j r| jr|d7 }| j  }| j \}}}t t |||t | j	  d|_
z | |||j
d |j
d  W n@ tk
r } z"| j | |t|d|d W 5 d }~X Y qX | j| q|s qq d S )Nr      )headersbufferr@   rA   queue_start_timecurl_start_timecurl_start_ioloop_timerb   ra   W  )r@   coderU   )r+   r.   poppopleftr   HTTPHeadersr   rD   r;   currentinfo_curl_setup_request	ExceptionrC   r   r%   r5   )r   startedr?   r@   rA   rc   r\   r   r   r   rE      s4    
		$z"CurlAsyncHTTPClient._process_queue)r?   
curl_errorcurl_messager   c           
      C   sd  |j }d |_ | j| | j| |d }|rj|d k	s<tt||}|d k	sRt|j}d }|  d }n&d }|	t
j}|	t
j}|d t|d |d  |	t
j|	t
j|	t
j|	t
j|	t
j|	t
j|	t
jd}	zN|d t|d ||d ||||d d	d | j |d  |d
 |	d
 W n$ tk
r^   | |d  Y nX d S )Nrb   r   re   rc   )queueZ
namelookupconnectZ
appconnectZpretransferZstarttransfertotalredirectrA   r@   ra   zX-Http-Reasonrd   )
r@   rg   ra   rb   effective_urlrU   reasonZrequest_time
start_time	time_info)rl   r%   r6   r+   rC   AssertionError	CurlErrorrg   r=   getinfor$   Z	HTTP_CODEZEFFECTIVE_URLseekdictZNAMELOOKUP_TIMEZCONNECT_TIMEZAPPCONNECT_TIMEZPRETRANSFER_TIMEZSTARTTRANSFER_TIMEZ
TOTAL_TIMEZREDIRECT_TIMEr   getr;   rD   rn   handle_callback_exception)
r   r?   rp   rq   rl   rb   rU   rg   rv   ry   r   r   r   r^     sX    









zCurlAsyncHTTPClient._finish)rA   r   c                 C   s   t jd|dd d S )NzException in callback %rT)exc_info)r   rU   )r   rA   r   r   r   r   7  s    z-CurlAsyncHTTPClient.handle_callback_exceptionc                 C   sl   t  }ttjr2|t jd |t j| j	 t
t drh|t jt jt jB  |t jt jt jB  |S )Nr`   	PROTOCOLS)r$   r4   curl_logisEnabledForloggingDEBUGr&   VERBOSEZDEBUGFUNCTION_curl_debughasattrr   Z
PROTO_HTTPZPROTO_HTTPSZREDIR_PROTOCOLSr>   r   r   r   r   :  s     z CurlAsyncHTTPClient._curl_create)r?   r@   rb   ra   r   c                    s    tjtj djkr(djd< djkr<djd<   tjdd j D    tjt	
j|j jrtttf tdfdd}n|j}  tj|   tjj   tjj jd k	st  tjtd	j  jd k	st  tjtd	j  jr<  tjtj n  tjd
 jrb  tj j j!rz  tj"d n  tj"d  j#rFj$rF  tj%j#   tj&j$ j'rj(d k	stt)*j'j(}  tj+| j,d ksj,dkr  tj-tj. n,j,dkr6  tj-tj/ nt0dj, nBz 1tj% W n$ t2k
rz     tj%d Y nX  1tj+ j3r  tj4d   tj5d n  tj4d   tj5d j6d k	r  tj7j6 n j8dkr  tj9tj: n  tj9tj; tj<tj=tj>tj?d}t@dddg}|A D ]}	  |	d qBjB|kr 1tjC   |jB d n4jDsjB|kr  tjCjB ntEdjB jBdk}
jFd k	}jDs|
r|r|r|
st0d|
rdndjBf |
s|rjBdkr&t0dtGtHjFp4dtd d fdd }  tjIjJ   tjK| jBd!kr  tjLtMjFpd n(  tj>d   tjNtMjFpd jOd k	rfjPd k	stjQd ksjQdkr  tjRtj. n,jQdkr"  tjRtj/ nt0d"jQ t)*jOjP}  tjS| tTUd#jBjjO n 1tjS tTUd$jBj jVd k	r  tjWjV jXd k	r  tjYjX jZd k	rt0d%t[\ dkr  tj]d j^d k	r^  d S )&NZExpect ZPragmac                 S   s0   g | ](\}}d t |dt |df qS )s   %s: %sASCIIz	ISO8859-1)r   encode)r   kvr   r   r   r    `  s   z;CurlAsyncHTTPClient._curl_setup_request.<locals>.<listcomp>)br   c                    s&    j d k	stj j |  t| S r9   )streaming_callbackrz   r;   add_callbacklen)r   )r@   r   r   r   write_functiono  s    z?CurlAsyncHTTPClient._curl_setup_request.<locals>.write_functionr!   z Mozilla/5.0 (compatible; pycurl)zgzip,deflatebasicdigestzUnsupported proxy_auth_mode %sr`      r   F)GETPOSTPUTHEADDELETEOPTIONSPATCHTzunknown method )r   r   r   zLBody must %sbe None for method %s (unless allow_nonstandard_methods is true)znot r   z!Body must be None for GET request)cmdr   c                    s   |  j krd d S rB   )ZIOCMD_RESTARTREADr}   )r   )r?   request_bufferr   r   ioctl  s    
z6CurlAsyncHTTPClient._curl_setup_request.<locals>.ioctlr   zUnsupported auth_mode %sz%s %s (username: %r)%s %sz,ssl_options not supported in curl_httpclient)_r&   r$   URLr   urlra   Z
HTTPHEADERget_allZHEADERFUNCTION	functoolspartial_curl_header_callbackheader_callbackr   r   bytes	bytearrayintwriteZWRITEFUNCTIONZFOLLOWLOCATIONZfollow_redirectsZ	MAXREDIRSmax_redirectsconnect_timeoutrz   ZCONNECTTIMEOUT_MSrequest_timeoutZ
TIMEOUT_MS
user_agentZ	USERAGENTZnetwork_interfaceZ	INTERFACEZdecompress_responseENCODINGZ
proxy_hostZ
proxy_portZPROXYZ	PROXYPORTZproxy_usernameZproxy_passwordr   Zencode_username_passwordZPROXYUSERPWDZproxy_auth_modeZ	PROXYAUTHZHTTPAUTH_BASICZHTTPAUTH_DIGEST
ValueErrorZunsetopt	TypeErrorZvalidate_certZSSL_VERIFYPEERZSSL_VERIFYHOSTca_certsZCAINFOZ
allow_ipv6Z	IPRESOLVEZIPRESOLVE_V4ZIPRESOLVE_WHATEVERZHTTPGETr   ZUPLOADZNOBODYsetvaluesmethodZCUSTOMREQUESTZallow_nonstandard_methodsKeyErrorbodyr   r   ZREADFUNCTIONreadZIOCTLFUNCTIONZPOSTFIELDSIZEr   Z
INFILESIZEZauth_usernameZauth_passwordZ	auth_modeZHTTPAUTHZUSERPWDr   debugclient_certZSSLCERTZ
client_keyZSSLKEYZssl_options	threadingactive_countZNOSIGNALZprepare_curl_callback)r   r?   r@   rb   ra   r   credentialsZcurl_optionsZcustom_methodsoZbody_expectedZbody_presentr   Zuserpwdr   )r?   r@   r   r   r   rm   F  s   




	    


 	z'CurlAsyncHTTPClient._curl_setup_request)ra   r   header_line_bytesr   c                 C   s   t |d}|d k	r$| j|| | }|drt|  zt|\}}}d| }W n tj	k
rr   Y d S X |s|d S |
| d S )Nlatin1zHTTP/zX-Http-Reason: %s)r   decoder;   r   rstrip
startswithclearr   Zparse_response_start_lineZHTTPInputError
parse_line)r   ra   r   r   Zheader_line__rw   r   r   r   r     s    
z)CurlAsyncHTTPClient._curl_header_callback)
debug_type	debug_msgr   c                 C   sv   d}|dkr&t |}td|  nL|dkrXt |}| D ]}td|| | q>n|dkrrtd|| | d S )N)I<>r   r   r   z%s)r`   r   r      z%s %r)r   r   r   strip
splitlines)r   r   r   Zdebug_typesliner   r   r   r   3  s    zCurlAsyncHTTPClient._curl_debug)r   N)NN)"__name__
__module____qualname__r   r   r   strr   r#   r=   r   r   r   rF   r   r(   r'   rP   rR   r1   rX   rE   r$   r4   r^   r   r   r   r   rj   rm   r   r   __classcell__r   r   r7   r   r   0   sT       " ,  6 Yr   c                   @   s   e Zd ZeeddddZdS )r{   N)errnomessager   c                 C   s   t | d| || _d S )Nrf   )r	   __init__r   )r   r   r   r   r   r   r   A  s    zCurlError.__init__)r   r   r   r   r   r   r   r   r   r   r{   @  s   r{   __main__)&__doc__r,   r   r   r$   r   rD   ior   Ztornador   r   Ztornado.escaper   r   Ztornado.httpclientr   r   r	   r
   r   Ztornado.logr   typingr   r   r   r   r   TYPE_CHECKINGr   r   	getLoggerr   r   r{   r   	configurer   r   r   r   <module>   s4   
    

