o
    Qœ_ÿ_  ã                   @   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mZ ddlZejredd
l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 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ÚTupleÚOptional)ÚDequeztornado.curl_httpclientc                
       s€  e Zd Z	d7dedeeeef  ddf‡ fdd„Zd8‡ fdd	„Z	d
e
deegdf ddfdd„Zdededededdf
dd„Zdeddfdd„Zdededdfdd„Zd8dd„Zd8dd„Zd8dd„Zd8d d!„Z		d9d"ejd#ee d$ee ddfd%d&„Zdeddfd'd(„Zdejfd)d*„Zd"ejd
e
d+ed,ejddf
d-d.„Zd,ejd/eegdf d0eddfd1d2„Zd3ed4eddfd5d6„Z ‡  Z!S ):Ú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   ú9/usr/lib/python3/dist-packages/tornado/curl_httpclient.pyÚ
<listcomp>9   s    z2CurlAsyncHTTPClient.initialize.<locals>.<listcomp>éè  )ÚsuperÚ
initializeÚpycurlÚ	CurlMultiÚ_multiÚsetoptÚM_TIMERFUNCTIONÚ_set_timeoutÚM_SOCKETFUNCTIONÚ_handle_socketÚrangeÚ_curlsÚ
_free_listÚcollectionsÚdequeÚ	_requestsÚ_fdsÚ_timeoutr   ÚPeriodicCallbackÚ_handle_force_timeoutÚ_force_timeout_callbackÚstartÚCurlÚ
add_handleÚremove_handle)r   r   r   Údummy_curl_handle©Ú	__class__r   r   r#   1   s"   
ÿÿ
zCurlAsyncHTTPClient.initializec                    sZ   | j  ¡  | jd ur| j | j¡ | jD ]}| ¡  q| j ¡  tƒ  ¡  d | _ d | _d S ©N)	r6   Ústopr3   Úio_loopÚremove_timeoutr-   Úcloser&   r"   ©r   Úcurlr<   r   r   rB   S   s   






zCurlAsyncHTTPClient.closeÚrequestÚcallbackc                 C   s.   | j  ||| j ¡ f¡ |  ¡  |  d¡ d S ©Nr   )r1   Úappendr@   ÚtimeÚ_process_queuer)   )r   rE   rF   r   r   r   Ú
fetch_implb   s   zCurlAsyncHTTPClient.fetch_implÚeventÚfdÚmultiÚdatac              	   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r2|| jv r0| j |¡ | j|= dS dS || }|| jv rA| j |¡ | j || j|¡ || j|< dS )z_Called by libcurl when it wants to change the file descriptors
        it cares about.
        N)r$   Ú	POLL_NONEr   ÚIOLoopÚNONEÚPOLL_INÚREADÚPOLL_OUTÚWRITEÚ
POLL_INOUTÚPOLL_REMOVEr2   r@   Úremove_handlerÚadd_handlerÚ_handle_events)r   rL   rM   rN   rO   Ú	event_mapÚioloop_eventr   r   r   r+   i   s   


ü

þ
	z"CurlAsyncHTTPClient._handle_socketÚmsecsc                 C   s<   | j dur| j | j ¡ | j | j ¡ |d  | j¡| _ dS )z(Called by libcurl to schedule a timeout.Ng     @�@)r3   r@   rA   Úadd_timeoutrI   Ú_handle_timeout)r   r^   r   r   r   r)   †   s
   

ÿz CurlAsyncHTTPClient._set_timeoutÚeventsc              
   C   s”   d}|t jj@ r|tjO }|t jj@ r|tjO }	 z| j ||¡\}}W n tj	y< } z|j
d }W Y d}~nd}~ww |tjkrCnq|  ¡  dS )zXCalled by IOLoop when there is activity on one of our
        file descriptors.
        r   TN)r   rQ   rT   r$   Ú
CSELECT_INrV   ÚCSELECT_OUTr&   Úsocket_actionÚerrorÚargsÚE_CALL_MULTI_PERFORMÚ_finish_pending_requests)r   rM   ra   ÚactionÚretÚnum_handlesÚer   r   r   r[   Ž   s    

€ÿ
úz"CurlAsyncHTTPClient._handle_eventsc              
   C   sŒ   d| _ 	 z| j tjd¡\}}W n tjy( } z|jd }W Y d}~nd}~ww |tjkr/nq|  ¡  | j 	¡ }|dkrD|  
|¡ dS dS )z7Called by IOLoop when the requested timeout has passed.NTr   )r3   r&   rd   r$   ÚSOCKET_TIMEOUTre   rf   rg   rh   Útimeoutr)   )r   rj   rk   rl   Únew_timeoutr   r   r   r`       s    €ÿ
ú
ÿz#CurlAsyncHTTPClient._handle_timeoutc              
   C   s`   	 z	| j  ¡ \}}W n tjy" } z|jd }W Y d}~nd}~ww |tjkr)nq|  ¡  dS )zpCalled by IOLoop periodically to ask libcurl to process any
        events it may have forgotten about.
        Tr   N)r&   Ú
socket_allr$   re   rf   rg   rh   )r   rj   rk   rl   r   r   r   r5   ½   s   €ÿ
úz)CurlAsyncHTTPClient._handle_force_timeoutc                 C   s\   	 | j  ¡ \}}}|D ]}|  |¡ q|D ]\}}}|  |||¡ q|dkr'nq|  ¡  dS )zbProcess any requests that were completed by the last
        call to multi.socket_action.
        Tr   N)r&   Ú	info_readÚ_finishrJ   )r   Únum_qÚok_listÚerr_listrD   ÚerrnumÚerrmsgr   r   r   rh   Ê   s   ùz,CurlAsyncHTTPClient._finish_pending_requestsc              
   C   sä   	 d}| j rm| jrm|d7 }| j  ¡ }| j ¡ \}}}t ¡ tƒ |||t ¡ | j 	¡  ¡ dœ|_
z|  |||j
d |j
d ¡ W n! ty` } z| j  |¡ |t|d|d�ƒ W Y d }~nd }~ww | j |¡ | j rm| js	|sqd S q)	NTr   é   )ÚheadersÚbufferrE   rF   Úqueue_start_timeÚcurl_start_timeÚcurl_start_ioloop_timerz   ry   éW  )rE   Úcodere   )r.   r1   ÚpopÚpopleftr   ÚHTTPHeadersr   rI   r@   ÚcurrentÚinfoÚ_curl_setup_requestÚ	ExceptionrH   r   r&   r9   )r   ÚstartedrD   rE   rF   r{   rl   r   r   r   rJ   Ø   s>   
ù	ü	€öß#Úz"CurlAsyncHTTPClient._process_queuerD   Ú
curl_errorÚcurl_messagec           
      C   s`  |j }d |_ | j |¡ | j |¡ |d }|r5|d usJ ‚t||ƒ}|d us)J ‚|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�}	z(|d t|d ||d ||||d  d	d ¡| j ¡ |d  |d
 |	d�
ƒ W d S  ty¯   |  |d ¡ Y d S w )Nrz   r   r}   r{   )ÚqueueÚ
namelookupÚconnectÚ
appconnectÚpretransferÚstarttransferÚtotalÚredirectrF   rE   ry   zX-Http-Reasonr|   )
rE   r   ry   rz   Úeffective_urlre   ÚreasonÚrequest_timeÚ
start_timeÚ	time_info)r„   r&   r:   r.   rH   Ú	CurlErrorr   rB   Úgetinfor$   Ú	HTTP_CODEÚEFFECTIVE_URLÚseekÚdictÚNAMELOOKUP_TIMEÚCONNECT_TIMEÚAPPCONNECT_TIMEÚPRETRANSFER_TIMEÚSTARTTRANSFER_TIMEÚ
TOTAL_TIMEÚREDIRECT_TIMEr   Úgetr@   rI   r†   Úhandle_callback_exception)
r   rD   rˆ   r‰   r„   rz   re   r   r’   r–   r   r   r   rr     sZ   








ø
ö
ÿÿzCurlAsyncHTTPClient._finishc                 C   s   t jd|dd� d S )NzException in callback %rT)Úexc_info)r   re   )r   rF   r   r   r   r¥   7  s   z-CurlAsyncHTTPClient.handle_callback_exceptionc                 C   sl   t  ¡ }t tj¡r| t jd¡ | t j| j	¡ t
t dƒr4| t jt jt jB ¡ | t jt jt jB ¡ |S )Nrx   Ú	PROTOCOLS)r$   r8   Úcurl_logÚisEnabledForÚloggingÚDEBUGr'   ÚVERBOSEÚDEBUGFUNCTIONÚ_curl_debugÚhasattrr§   Ú
PROTO_HTTPÚPROTO_HTTPSÚREDIR_PROTOCOLSrC   r   r   r   r   :  s   ÿz CurlAsyncHTTPClient._curl_createrz   ry   c                    sü  ˆ   tjtˆjƒ¡ dˆjvrdˆjd< dˆjvrdˆjd< ˆ   tjdd„ ˆj ¡ D ƒ¡ ˆ   tjt	 
ˆj|ˆj¡¡ ˆjrOdtttf dtf‡‡fdd	„}n|j}ˆ   tj|¡ ˆ   tjˆj¡ ˆ   tjˆj¡ ˆjd uspJ ‚ˆ   tjtd
ˆj ƒ¡ ˆjd usƒJ ‚ˆ   tjtd
ˆj ƒ¡ ˆjr�ˆ   tjtˆjƒ¡ nˆ   tjd¡ ˆjr¯ˆ   tjˆj¡ ˆj rºˆ   tj!d¡ nˆ   tj!d ¡ ˆj"�rˆj#�rˆ   tj$ˆj"¡ ˆ   tj%ˆj#¡ ˆj&ròˆj'd usãJ ‚t( )ˆj&ˆj'¡}ˆ   tj*|¡ ˆj+d u sýˆj+dk�rˆ   tj,tj-¡ n6ˆj+dk�rˆ   tj,tj.¡ n't/dˆj+ ƒ‚zˆ  0tj$¡ W n t1�y5   ˆ   tj$d¡ Y nw ˆ  0tj*¡ ˆj2�rOˆ   tj3d¡ ˆ   tj4d¡ nˆ   tj3d¡ ˆ   tj4d¡ ˆj5d u�rlˆ   tj6ˆj5¡ n	 ˆj7du �r|ˆ   tj8tj9¡ nˆ   tj8tj:¡ tj;tj<tj=tj>dœ}t?g d¢ƒ}| @¡ D ]	}	ˆ   |	d¡ �q™ˆjA|v �r¹ˆ  0tjB¡ ˆ   |ˆjA d¡ nˆjC�sÃˆjA|v �rÌˆ   tjBˆjA¡ ntDdˆjA ƒ‚ˆjAdv }
ˆjEd u}ˆjC�sû|
�rç|�rí|�rû|
�sût/d|
�rôdndˆjAf ƒ‚|
�s|�rXˆjAdk�rt/dƒ‚tFtGˆjE�pdƒƒ‰dtdd f‡ ‡fdd„}ˆ   tjHˆjI¡ ˆ   tjJ|¡ ˆjAd k�rDˆ   tjKtLˆjE�p@dƒ¡ nˆ   tj=d¡ ˆ   tjMtLˆjE�pUdƒ¡ ˆjNd u�r¬ˆjOd u�sfJ ‚ˆjPd u �srˆjPdk�r{ˆ   tjQtj-¡ nˆjPdk�rŠˆ   tjQtj.¡ nt/d!ˆjP ƒ‚t( )ˆjNˆjO¡}ˆ   tjR|¡ tS Td"ˆjAˆjˆjN¡ nˆ  0tjR¡ tS Td#ˆjAˆj¡ ˆjUd u�rÉˆ   tjVˆjU¡ ˆjWd u�r×ˆ   tjXˆjW¡ ˆjYd u�rát/d$ƒ‚tZ [¡ dk�rïˆ   tj\d¡ ˆj]d u�rüˆ ]ˆ ¡ d S d S )%NÚExpectÚ ÚPragmac                 S   s$   g | ]\}}d t |ƒt |ƒf ‘qS )z%s: %s)r   )r   ÚkÚvr   r   r   r    `  s    ÿÿz;CurlAsyncHTTPClient._curl_setup_request.<locals>.<listcomp>Úbr   c                    s&   ˆ j d usJ ‚ˆj ˆ j | ¡ t| ƒS r>   )Ústreaming_callbackr@   Úadd_callbackÚlen)r¸   )rE   r   r   r   Úwrite_functionn  s   z?CurlAsyncHTTPClient._curl_setup_request.<locals>.write_functionr!   z Mozilla/5.0 (compatible; pycurl)zgzip,deflateÚbasicÚdigestzUnsupported proxy_auth_mode %srx   é   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Úcmdc                    s   | ˆ j krˆ d¡ d S d S rG   )ÚIOCMD_RESTARTREADr›   )rÇ   )rD   Ú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   Úurlry   Ú
HTTPHEADERÚget_allÚHEADERFUNCTIONÚ	functoolsÚpartialÚ_curl_header_callbackÚheader_callbackr¹   r   ÚbytesÚ	bytearrayÚintÚwriteÚWRITEFUNCTIONÚFOLLOWLOCATIONÚfollow_redirectsÚ	MAXREDIRSÚmax_redirectsÚconnect_timeoutÚCONNECTTIMEOUT_MSÚrequest_timeoutÚ
TIMEOUT_MSÚ
user_agentÚ	USERAGENTÚnetwork_interfaceÚ	INTERFACEÚdecompress_responseÚENCODINGÚ
proxy_hostÚ
proxy_portÚPROXYÚ	PROXYPORTÚproxy_usernameÚproxy_passwordr   Úencode_username_passwordÚPROXYUSERPWDÚproxy_auth_modeÚ	PROXYAUTHÚHTTPAUTH_BASICÚHTTPAUTH_DIGESTÚ
ValueErrorÚunsetoptÚ	TypeErrorÚvalidate_certÚSSL_VERIFYPEERÚSSL_VERIFYHOSTÚca_certsÚCAINFOÚ
allow_ipv6Ú	IPRESOLVEÚIPRESOLVE_V4ÚIPRESOLVE_WHATEVERÚHTTPGETrÁ   ÚUPLOADÚNOBODYÚsetÚvaluesÚmethodÚCUSTOMREQUESTÚallow_nonstandard_methodsÚKeyErrorÚbodyr   r   ÚREADFUNCTIONÚreadÚIOCTLFUNCTIONÚPOSTFIELDSIZEr»   Ú
INFILESIZEÚauth_usernameÚauth_passwordÚ	auth_modeÚHTTPAUTHÚUSERPWDr¨   ÚdebugÚclient_certÚSSLCERTÚ
client_keyÚSSLKEYÚssl_optionsÚ	threadingÚactive_countÚNOSIGNALÚprepare_curl_callback)r   rD   rE   rz   ry   r¼   ÚcredentialsÚcurl_optionsÚcustom_methodsÚoÚbody_expectedÚbody_presentrÊ   Úuserpwdr   )rD   rE   rÉ   r   r   r…   F  s  




þþ
ÿþ"ÿÿÿü

ÿÿþÿÿü	ÿz'CurlAsyncHTTPClient._curl_setup_requestrÔ   Úheader_line_bytesc                 C   sˆ   t | d¡ƒ}|d ur| j ||¡ | ¡ }| d¡r9| ¡  zt |¡\}}}d| }W n tj	y8   Y d S w |s=d S | 
|¡ d S )NÚlatin1zHTTP/zX-Http-Reason: %s)r   Údecoder@   rº   ÚrstripÚ
startswithÚclearr   Úparse_response_start_lineÚHTTPInputErrorÚ
parse_line)r   ry   rÔ   r%  Úheader_lineÚ__r“   r   r   r   rÓ     s   
ÿz)CurlAsyncHTTPClient._curl_header_callbackÚ
debug_typeÚ	debug_msgc                 C   s~   d}|dkrt |ƒ}t d| ¡ ¡ d S |dv r.t |ƒ}| ¡ D ]}t d|| |¡ q d S |dkr=t d|| |¡ d S d S )N)ÚIú<ú>r3  r4  r   z%s)rx   r¿   rË   é   z%s %r)r   r¨   r  ÚstripÚ
splitlines)r   r0  r1  Údebug_typesÚliner   r   r   r®   2  s   ÿÿzCurlAsyncHTTPClient._curl_debug)r   N)r   N)NN)"Ú__name__Ú
__module__Ú__qualname__r×   r   r   Ústrr   r#   rB   r   r   r   rK   rÕ   r+   r)   r[   r`   r5   rh   rJ   r$   r8   rr   r¥   r   r   r   r‚   r…   rÓ   r®   Ú__classcell__r   r   r<   r   r   0   sv    ÿÿÿþ"ÿÿ
þ



,üþýü
û6þýüû
ú Vþýü
ûr   c                   @   s"   e Zd Zdededdfdd„ZdS )r—   ÚerrnoÚmessager   Nc                 C   s   t  | d|¡ || _d S )Nr~   )r	   Ú__init__r?  )r   r?  r@  r   r   r   rA  @  s   
zCurlError.__init__)r:  r;  r<  r×   r=  rA  r   r   r   r   r—   ?  s    r—   Ú__main__)&Ú__doc__r/   rÑ   rª   r$   r  rI   Úior   Útornador   r   Útornado.escaper   r   Útornado.httpclientr   r   r	   r
   r   Útornado.logr   Útypingr   r   r   r   r   r   ÚTYPE_CHECKINGr   Ú	getLoggerr¨   r   r—   r:  Ú	configurer   r   r   r   Ú<module>   s8    
    

þ