B
    £ä˜\9^  ã               @   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 ddlZejrÊdd
lmZ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)ÚDequeÚTupleÚOptionalztornado.curl_httpclientc                   sR  e Zd Zd.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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 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   ú6lib/python3.7/site-packages/tornado/curl_httpclient.pyú
<listcomp>8   s    z2CurlAsyncHTTPClient.initialize.<locals>.<listcomp>iè  )Úsuperr   Ú
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                sb   | j  ¡  | jd k	r"| j | j¡ x| jD ]}| ¡  q*W | j ¡  tt	| ƒ ¡  d | _ d | _d S )N)
r0   Ústopr.   Úio_loopÚremove_timeoutr(   Úcloser#   r    r   )r   Úcurl)r5   r   r   r9   R   s    


zCurlAsyncHTTPClient.close)ÚrequestÚcallbackr   c             C   s.   | j  ||| j ¡ f¡ |  ¡  |  d¡ d S )Nr   )r,   Úappendr7   ÚtimeÚ_process_queuer%   )r   r;   r<   r   r   r   Ú
fetch_impla   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   ÚIOLoopZNONEZPOLL_INÚREADZPOLL_OUTÚWRITEZ
POLL_INOUTZPOLL_REMOVEr-   r7   Zremove_handlerZadd_handlerÚ_handle_events)r   rA   rB   rC   rD   Z	event_mapZioloop_eventr   r   r   r&   h   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     @@)r.   r7   r8   Zadd_timeoutr>   Ú_handle_timeout)r   rI   r   r   r   r%   …   s    
z CurlAsyncHTTPClient._set_timeout)rB   Úeventsr   c          
   C   s”   d}|t jj@ r|tjO }|t jj@ r0|tjO }xVy| j ||¡\}}W n. tj	k
rv } z|j
d }W dd}~X Y nX |tjkr2P q2W |  ¡  dS )zXCalled by IOLoop when there is activity on one of our
        file descriptors.
        r   N)r   rE   rF   r"   Z
CSELECT_INrG   ZCSELECT_OUTr#   Úsocket_actionÚerrorÚargsÚE_CALL_MULTI_PERFORMÚ_finish_pending_requests)r   rB   rK   ÚactionÚretÚnum_handlesÚer   r   r   rH      s    


z"CurlAsyncHTTPClient._handle_eventsc          
   C   sˆ   d| _ xXy| j tjd¡\}}W n. tjk
rN } z|jd }W dd}~X Y nX |tjkrP qW |  ¡  | j 	¡ }|dkr„|  
|¡ dS )z7Called by IOLoop when the requested timeout has passed.Nr   )r.   r#   rL   r"   ZSOCKET_TIMEOUTrM   rN   rO   rP   Ztimeoutr%   )r   rR   rS   rT   Znew_timeoutr   r   r   rJ   Ÿ   s    

z#CurlAsyncHTTPClient._handle_timeoutc          
   C   s`   xRy| j  ¡ \}}W n. tjk
rB } z|jd }W dd}~X Y nX |tjkrP qW |  ¡  dS )zpCalled by IOLoop periodically to ask libcurl to process any
        events it may have forgotten about.
        r   N)r#   Z
socket_allr"   rM   rN   rO   rP   )r   rR   rS   rT   r   r   r   r/   ¼   s    
z)CurlAsyncHTTPClient._handle_force_timeoutc             C   sf   xX| j  ¡ \}}}x|D ]}|  |¡ qW x |D ]\}}}|  |||¡ q0W |dkrP qW |  ¡  dS )zbProcess any requests that were completed by the last
        call to multi.socket_action.
        r   N)r#   Z	info_readÚ_finishr?   )r   Znum_qZok_listZerr_listr:   ZerrnumÚerrmsgr   r   r   rP   É   s    
z,CurlAsyncHTTPClient._finish_pending_requestsc          
   C   sà   xÚd}xÊ| j rÐ| jrÐ|d7 }| j  ¡ }| j ¡ \}}}t ¡ tƒ |||t ¡ | j 	¡  ¡ dœ|_
y |  |||j
d |j
d ¡ W n@ tk
rÀ } z"| j  |¡ |t|d|dƒ W d d }~X Y qX | j |¡ qW |sP qW d S )Nr   é   )ÚheadersÚbufferr;   r<   Úqueue_start_timeÚcurl_start_timeÚcurl_start_ioloop_timerY   rX   iW  )r;   ÚcoderM   )r)   r,   ÚpopÚpopleftr   ÚHTTPHeadersr   r>   r7   ZcurrentÚinfoÚ_curl_setup_requestÚ	Exceptionr=   r   r#   r3   )r   Zstartedr:   r;   r<   rZ   rT   r   r   r   r?   ×   s,    
	$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}	yN|d t|d ||d ||||d  d	d ¡| j ¡ |d  |d
 |	d
ƒ W n$ tk
r^   |  |d ¡ Y nX d S )NrY   r   r\   rZ   )ZqueueZ
namelookupZconnectZ
appconnectZpretransferZstarttransferZtotalZredirectr<   r;   rX   zX-Http-Reasonr[   )
r;   r]   rX   rY   Úeffective_urlrM   ÚreasonZrequest_timeZ
start_timeÚ	time_info)ra   r#   r4   r)   r=   ÚAssertionErrorÚ	CurlErrorr]   r9   Zgetinfor"   Z	HTTP_CODEZEFFECTIVE_URLÚseekÚdictZNAMELOOKUP_TIMEZCONNECT_TIMEZAPPCONNECT_TIMEZPRETRANSFER_TIMEZSTARTTRANSFER_TIMEZ
TOTAL_TIMEZREDIRECT_TIMEr   Úgetr7   r>   rc   Úhandle_callback_exception)
r   r:   rd   re   ra   rY   rM   r]   rf   rh   r   r   r   rU   ü   sR    







zCurlAsyncHTTPClient._finish)r<   r   c             C   s   t jd|dd d S )NzException in callback %rT)Úexc_info)r   rM   )r   r<   r   r   r   rn   /  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 )NrW   Ú	PROTOCOLS)r"   r2   Úcurl_logZisEnabledForÚloggingÚDEBUGr$   ÚVERBOSEZDEBUGFUNCTIONÚ_curl_debugÚhasattrrp   Z
PROTO_HTTPZPROTO_HTTPSZREDIR_PROTOCOLS)r   r:   r   r   r   r   2  s    z CurlAsyncHTTPClient._curl_create)r:   r;   rY   rX   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rœtttf tdœ‡‡fdd„}n|j}ˆ   tj|¡ ˆ   tjˆj¡ ˆ   tjˆj¡ ˆjd k	sÞt‚ˆ   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	sÐt‚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, ƒ‚nˆ   tj%d¡ ˆ  1tj+¡ ˆj2r†ˆ   tj3d¡ ˆ   tj4d¡ nˆ   tj3d¡ ˆ   tj4d¡ ˆj5d k	rÀˆ   tj6ˆj5¡ n ˆj7dkrÞˆ   tj8tj9¡ nˆ   tj8tj:¡ tj;tj<tj=tj>dœ}t?dddgƒ}x| @¡ D ]}	ˆ   |	d¡ qW ˆjA|kr^ˆ  1tjB¡ ˆ   |ˆjA d¡ n4ˆjCsrˆjA|kr„ˆ   tjBˆjA¡ ntDdˆjA ƒ‚ˆjAdk}
ˆjEd k	}ˆjCsâ|
rº|rÆ|râ|
sât0d|
rÔdndˆjAf ƒ‚|
sî|ršˆjAdkrt0dƒ‚tFtGˆjEpdƒƒ‰td dœ‡ ‡fd d!„}ˆ   tjHˆjI¡ ˆ   tjJ|¡ ˆjAd"krrˆ   tjKtLˆjEpjdƒ¡ n(ˆ   tj=d¡ ˆ   tjMtLˆjEp”dƒ¡ ˆjNd k	rBˆjOd k	s¶t‚ˆjPd ksÎˆjPdkràˆ   tjQtj.¡ n,ˆjPdkrþˆ   tjQtj/¡ nt0d#ˆjP ƒ‚t) *ˆjNˆjO¡}ˆ   tjR|¡ tS Td$ˆjAˆjˆjN¡ nˆ  1tjR¡ tS Td%ˆjAˆj¡ ˆjUd k	r|ˆ   tjVˆjU¡ ˆjWd k	r˜ˆ   tjXˆjW¡ ˆjYd k	r¬t0d&ƒ‚tZ [¡ dkrÈˆ   tj\d¡ ˆj]d k	rÞˆ ]ˆ ¡ d S )'NZExpectÚ ZPragmac             S   s$   g | ]\}}d t |ƒt |ƒf ‘qS )z%s: %s)r   )r   ÚkÚvr   r   r   r   Y  s   z;CurlAsyncHTTPClient._curl_setup_request.<locals>.<listcomp>)Úbr   c                s&   ˆ j d k	st‚ˆj ˆ j | ¡ t| ƒS )N)Ústreaming_callbackri   r7   Úadd_callbackÚlen)rz   )r;   r   r   r   Úwrite_functionf  s    z?CurlAsyncHTTPClient._curl_setup_request.<locals>.write_functioniè  z Mozilla/5.0 (compatible; pycurl)zgzip,deflateZnoneZbasicZdigestzUnsupported proxy_auth_mode %srW   é   r   F)ÚGETÚPOSTÚPUTZHEADZDELETEZ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 )Nr   )ZIOCMD_RESTARTREADrk   )r„   )r:   Úrequest_bufferr   r   Úioctl×  s    
z6CurlAsyncHTTPClient._curl_setup_request.<locals>.ioctlr   zUnsupported auth_mode %sz%s %s (username: %r)z%s %sz,ssl_options not supported in curl_httpclient)^r$   r"   ZURLr   ZurlrX   Z
HTTPHEADERZget_allZHEADERFUNCTIONÚ	functoolsÚpartialÚ_curl_header_callbackÚheader_callbackr{   r   ÚbytesÚ	bytearrayÚintÚwriteZWRITEFUNCTIONZFOLLOWLOCATIONZfollow_redirectsZ	MAXREDIRSZmax_redirectsZconnect_timeoutri   ZCONNECTTIMEOUT_MSZrequest_timeoutZ
TIMEOUT_MSZ
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unsetoptZvalidate_certZSSL_VERIFYPEERZSSL_VERIFYHOSTZca_certsZCAINFOZ
allow_ipv6Z	IPRESOLVEZIPRESOLVE_V4ZIPRESOLVE_WHATEVERZHTTPGETr   ZUPLOADZNOBODYÚsetÚvaluesÚmethodZCUSTOMREQUESTZallow_nonstandard_methodsÚKeyErrorZbodyr   r   ZREADFUNCTIONÚreadZIOCTLFUNCTIONZPOSTFIELDSIZEr}   Z
INFILESIZEZauth_usernameZauth_passwordZ	auth_modeZHTTPAUTHZUSERPWDrq   ÚdebugZclient_certZSSLCERTZ
client_keyZSSLKEYZssl_optionsÚ	threadingZactive_countZNOSIGNALZprepare_curl_callback)r   r:   r;   rY   rX   r~   ZcredentialsZcurl_optionsZcustom_methodsÚoZbody_expectedZbody_presentr†   Zuserpwdr   )r:   r;   r…   r   r   rb   >  sè    




 




	z'CurlAsyncHTTPClient._curl_setup_request)rX   rŠ   Úheader_line_bytesr   c             C   sˆ   t | d¡ƒ}|d k	r$| j ||¡ | ¡ }| d¡rr| ¡  yt |¡\}}}d| }W n tj	k
rp   d S X |szd S | 
|¡ d S )NÚlatin1zHTTP/zX-Http-Reason: %s)r   Údecoder7   r|   ÚrstripÚ
startswithÚclearr   Zparse_response_start_lineZHTTPInputErrorZ
parse_line)r   rX   rŠ   r™   Zheader_lineÚ__rg   r   r   r   r‰     s    
z)CurlAsyncHTTPClient._curl_header_callback)Ú
debug_typeÚ	debug_msgr   c             C   sz   d}|dkr&t |ƒ}t d| ¡ ¡ nP|dkr\t |ƒ}x>| ¡ D ]}t d|| |¡ q@W n|dkrvt d|| |¡ d S )N)ÚIú<ú>r£   r¤   r   z%s)rW   r   z%s %sé   z%s %r)r   rq   r–   ÚstripÚ
splitlines)r   r    r¡   Zdebug_typesÚliner   r   r   ru   '  s    zCurlAsyncHTTPClient._curl_debug)r   N)NN)!Ú__name__Ú
__module__Ú__qualname__r   r   Ústrr   r!   r9   r   r   r   r@   r‹   r&   r%   rH   rJ   r/   rP   r?   r"   r2   rU   rn   r   r   r   r`   rb   r‰   ru   Ú__classcell__r   r   )r5   r   r   0   s6   &
1 Or   c               @   s   e Zd Zeeddœdd„ZdS )rj   N)ÚerrnoÚmessager   c             C   s   t  | d|¡ || _d S )NiW  )r	   Ú__init__r®   )r   r®   r¯   r   r   r   r°   5  s    zCurlError.__init__)r©   rª   r«   r   r¬   r°   r   r   r   r   rj   4  s   rj   Ú__main__)&Ú__doc__r*   r‡   rr   r"   r—   r>   Úior   Ztornador   r   Ztornado.escaper   r   Ztornado.httpclientr   r   r	   r
   r   Ztornado.logr   Útypingr   r   r   r   ZTYPE_CHECKINGr   r   r   Z	getLoggerrq   r   rj   r©   Z	configurer   r   r   r   Ú<module>   s4   
    

