o
    ÙKÕii;  ã                   @   s²  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Zd dl	Z	d dl
mZmZmZmZmZmZ d dlmZmZ d dlmZmZ d dlmZmZmZmZ dZdZdZd	Zd
Z e !e "e#¡¡Z$edde%fdee&e&f fde'fgƒZ(edde%fdee&e&f fde&fdee&ef fdee fgƒZ)de&de*fdd„Z+de&dee& de&dee& fdd„Z,i a-dee& dee& ddfdd„Z.dee&e&f fdd „Z/dej0j1dee&e&f fd!d"„Z2	d@d#ej3d$ee% de(fd%d&„Z4d'd(„ Z5d)d*„ Z6		dAd#ej3d$ee% dee& de(fd+d,„Z7dee fd-d.„Z8de&fd/d0„Z9	dAde&d$ee% dee'e&f fd1d2„Z:di ddd3fde&d4ee' dee&e&f d5ee& d$ee% d6e*de)fd7d8„Z;	9dBd:e&d;e&d<e&d=e&de)f
d>d?„Z<dS )Cé    N)ÚAnyÚDictÚListÚ
NamedTupleÚOptionalÚTuple)ÚerrorÚrequest)ÚParseResultÚurlparse)ÚdefaultsÚ
exceptionsÚsystemÚutil)z169.254.169.254Úmetadataz[fd00:ec2::254]zhttp://archive.ubuntu.comzhttps://esm.ubuntu.comzhttp://api.snapcraft.iozhttps://api.snapcraft.ioÚUnparsedHTTPResponseÚcodeÚheadersÚbodyÚHTTPResponseÚ	json_dictÚ	json_listÚurlÚreturnc                 C   sR   zt | ƒ}W n
 ty   Y dS w |jdvrdS z|j W dS  ty(   Y dS w )NF)ÚhttpsÚhttpT)r   Ú
ValueErrorÚschemeÚport)r   Ú
parsed_url© r    ú8/usr/lib/python3/dist-packages/uaclient/http/__init__.pyÚis_service_url+   s   ÿ
ýÿr"   ÚprotocolÚproxyÚtest_urlc                 C   sF  |sd S t |ƒstj|d�‚tj|dd�}| dkrjt|ƒjdkrjzt||d�}W n4 tjy1   ‚  tj	y9   ‚  tj
yA   ‚  ty\ } zt d||t|ƒ¡ tj|d�‚d }~ww |jdkrd|S tj|d�‚t | |i¡}t |¡}z| |¡ |W S  tjtjfy¢ } zt d||t|d	t|ƒƒ¡ tj|d�‚d }~ww )
N)r$   ÚHEAD)Úmethodr   ©Úhttps_proxyz:Error trying to use "%s" as pycurl proxy to reach "%s": %séÈ   z:Error trying to use "%s" as urllib proxy to reach "%s": %sÚreason)r"   r   ÚProxyInvalidUrlr	   ÚRequestr   r   Ú_readurl_pycurl_https_in_httpsÚPycurlRequiredErrorÚProxyAuthenticationFailedÚPycurlCACertificatesErrorÚ	ExceptionÚLOGr   ÚstrÚProxyNotWorkingErrorr   ÚProxyHandlerÚbuild_openerÚopenÚsocketÚtimeoutÚURLErrorÚgetattr)r#   r$   r%   ÚreqÚresponseÚeÚproxy_handlerÚopenerr    r    r!   Úvalidate_proxy<   sT   ü€ù
	

ü€ùrB   Ú
http_proxyr)   c                 C   sÂ   i }| r| |d< |r||d< d  ttƒ¡}dD ]}tj |¡}|r2d  tt| d¡ƒ ttƒ¡ƒ¡}qt	 
d|¡ |tjd< |tjd< |rTt |¡}t |¡}t |¡ t	j
dd	|id
� |adS )aW  
    Globally configure pro-client to use http and https proxies.

    - sets global proxy configuration for urllib
    - sets the no_proxy environment variable for the current process
      which gets inherited for all subprocesses
    - sets module variable for use in https-in-https pycurl requests
      this is retrieved later using get_configured_web_proxy

    :param http_proxy: http proxy to be used by urllib. If None, it will
                       not be configured
    :param https_proxy: https proxy to be used by urllib. If None, it will
                        not be configured
    r   r   ú,)Úno_proxyÚNO_PROXYzSetting no_proxy: %srE   rF   zSetting global proxy dictÚextra)rG   N)ÚjoinÚsortedÚUA_NO_PROXY_URLSÚosÚenvironÚgetÚsetÚsplitÚunionr3   Údebugr	   r6   r7   Úinstall_openerÚ_global_proxy_dict)rC   r)   Ú
proxy_dictrE   Úenv_varÚproxy_valuer@   rA   r    r    r!   Úconfigure_web_proxyq   s0   ÿÿ€




rW   c                   C   s   t S ©N)rS   r    r    r    r!   Úget_configured_web_proxy¢   s   rY   c                 C   s   dd„ |   ¡ D ƒS )Nc                 S   s   i | ]	\}}|  ¡ |“qS r    )Úlower)Ú.0ÚkÚvr    r    r!   Ú
<dictcomp>¨   s    z$_headers_to_dict.<locals>.<dictcomp>)Úitems©r   r    r    r!   Ú_headers_to_dict¦   s   ra   r=   r:   c              
   C   s”   z	t j| |d�}W n1 tjy } z|}W Y d }~n!d }~w tjy: } zt t|jƒ¡ t	j
|| jd�‚d }~ww | ¡ }t|jt|jƒ|d�S )N©r:   )Úcauser   ©r   r   r   )r	   Úurlopenr   Ú	HTTPErrorr;   r3   Ú	exceptionr4   r+   r   ÚConnectivityErrorÚfull_urlÚreadr   r   ra   r   )r=   r:   Úrespr?   r   r    r    r!   Ú_readurl_urllib«   s    €€þýrl   c                 C   sJ   t |ƒ}t| ƒ}|jdkot |j¡ o|duo|jdk}t d|¡ |S )aµ  
    We only want to use pycurl if all of the following are true

    - The target url scheme is https
    - The target host is not in no_proxy
    - An https_proxy is configured either via pro's config or via environment
    - The https_proxy url scheme is https

    urllib.request provides some helpful functions that we re-use here.

    This function also returns the https_proxy to use, since it is calculated
    here anyway.
    r   NzShould use pycurl: %r)r   Ú_parse_https_proxyr   r	   Úproxy_bypassÚhostnamer3   rQ   )r)   Ú
target_urlÚparsed_target_urlÚparsed_https_proxyÚretr    r    r!   Úshould_use_pycurlÀ   s   
ÿþürt   c                 C   st   d }d }t | jƒdkr| jd }t | jƒdkr| jd }||kr*|r*d|v r*t ¡ ‚||kr4tj|d�‚tj| d�‚)Nr   é   Ú407©r   )r?   )ÚlenÚargsr   r0   r1   ÚPycurlError)r   r   Úauthentication_error_codeÚca_certificates_error_coder   Úmsgr    r    r!   Ú_handle_pycurl_errorÚ   s   

r~   c              
      s  zdd l }W n ty   t ¡ ‚w | ¡ }|  ¡  ¡ }|dkr(| |jd¡ n*|dkr4| |j	d¡ n|dkrK| |j
d¡ | jrJ| |j| j¡ ntd |¡ƒ‚| |j|  ¡ ¡ dd„ |  ¡ D ƒ}t|ƒdkrq| |j|¡ | |jd¡ | |jtj¡ |r‰| |j|¡ |r¦t|ƒ}|r•| ¡ nd }| |j|¡ | |jd	¡ nt d
¡ t  ¡ }| |j!|¡ i ‰ ‡ fdd„}	| |j"|	¡ z| #¡  W n |j$yê }
 zt%|
|  ¡ |j&|j'd� W Y d }
~
nd }
~
ww t(| )|j*¡ƒ}| +¡ }| ,¡  t-|ˆ |d�S )Nr   ÚGETTr&   ÚPOSTz5HTTP method "{}" not supported in HTTPS-in-HTTPS modec                 S   s   g | ]
\}}d   ||¡‘qS )z{}: {}©Úformat)r[   ÚnameÚvalr    r    r!   Ú
<listcomp>  s    ÿz2_readurl_pycurl_https_in_https.<locals>.<listcomp>é   z1in pycurl request function without an https proxyc                    sF   |   d¡} d| vrd S |  dd¡\}}| ¡  ¡ }| ¡ }|ˆ |< d S )Nz
iso-8859-1ú:ru   )ÚdecoderO   ÚstriprZ   )Úheader_lineÚname_rawÚ	value_rawrƒ   Úvaluer`   r    r!   Úsave_header(  s   
z3_readurl_pycurl_https_in_https.<locals>.save_header)r   r{   r|   rd   ).ÚpycurlÚImportErrorr   r/   ÚCurlÚ
get_methodÚupperÚsetoptÚHTTPGETÚNOBODYr€   ÚdataÚCOPYPOSTFIELDSr   r‚   ÚURLÚget_full_urlÚheader_itemsrx   Ú
HTTPHEADERÚFOLLOWLOCATIONÚCAINFOr   ÚSSL_CERTS_PATHÚTIMEOUTrm   ÚgeturlÚPROXYÚ	PROXYTYPEr3   ÚwarningÚioÚBytesIOÚ	WRITEDATAÚHEADERFUNCTIONÚperformr   r~   ÚE_RECV_ERRORÚE_SSL_CACERT_BADFILEÚintÚgetinfoÚRESPONSE_CODEÚgetvalueÚcloser   )r=   r:   r)   r�   Úcr'   Úheader_str_listrr   Úbody_outputrŽ   r?   r   r   r    r`   r!   r.   ë   s|   ÿ€ÿÿÿÿ
	ü€ÿýr.   c                 C   s"   | s	t  ¡  d¡} | rt| ƒS d S )Nr   )r	   Ú
getproxiesrM   r   r(   r    r    r!   rm   J  s   rm   c                 C   sH   | j  d¡}i }|si }ntj |¡si }nt t |¡¡}| |g ¡S )NÚserviceclient_url_responses)	ÚfeaturesrM   rK   ÚpathÚexistsÚjsonÚloadsr   Ú	load_file)Úcfgr   Úresponse_overlay_pathÚresponse_overlayr    r    r!   Ú_get_overlay_dataP  s   r¿   c              
   C   s¼  t | |ƒ}|r+| d¡}t |d d ¡�}| ¡ dfW  d   ƒ S 1 s&w   Y  t|ƒs5tj|d�‚t 	d 
|¡¡ tƒ  d¡}i }|rK||d< t||ƒrsttj||d	�||d
�}|jdkrgtj|d�‚t |j¡|j d¡fS tj||d	�}	zAt |	¡�1}t |¡�}| ¡ |j d¡fW  d   ƒ W  d   ƒ W S 1 s£w   Y  W d   ƒ W d S 1 s´w   Y  W d S  tjyÝ }
 z|
jdkrÏtj|d�‚|
jdkrØt ¡ ‚‚ d }
~
ww )Nr   r>   Ú	file_pathÚ rw   zURL [GET]: {}r   zIf-None-Matchr`   ©r:   r)   i0  ÚetagÚETagi”  )r¿   ÚpopÚlzmar8   rj   r"   r   Ú
InvalidUrlr3   rQ   r‚   rY   rM   rt   r.   r	   r-   r   ÚETagUnchangedÚ
decompressr   r   re   r   rf   ÚVulnerabilityDataNotFound)r¼   r   r:   rÃ   Úoverlay_responser>   Úfr)   r   r=   r?   r    r    r!   Údownload_xz_file_from_url^  sV   


 ÿ
ý


þ
þÿÿ&ÿ

€úrÍ   Tr—   r'   Úlog_response_bodyc              
      sŒ  t | ƒs
tj| d�‚|r|sd}tj| |ˆ |d�}d ‡ fdd„tˆ ƒD ƒ¡}t d 	|p.d| ||r7| 
d	¡nd ¡¡ tƒ  d
¡}t|| ƒrNt|||d�‰nt||d�‰ˆjj
d	dd�}	i }
g }dˆj dd¡v r‰tj|	tjd�}t|tƒry|}
nt|tƒr�|}nt dt|ƒ¡ d ‡fdd„tˆjƒD ƒ¡}d 	|p�d| |¡}|r¶ˆj}|
r«|
}n|r¯|}|d 	|¡7 }t |¡ tˆjˆj|	|
|d�S )Nrw   r€   )r—   r   r'   z, c                    s   g | ]
}d   |ˆ | ¡‘qS ©z
'{}': '{}'r�   ©r[   r\   r`   r    r!   r…   ¢  s    zreadurl.<locals>.<listcomp>z'URL [{}]: {}, headers: {{{}}}, data: {}r   úutf-8r   rÂ   rb   Úignore©Úerrorsúapplication/jsonúcontent-typerÁ   ©Úclsúunexpected JSON response: %sc                    s   g | ]}d   |ˆ j| ¡‘qS rÏ   )r‚   r   rÐ   )rk   r    r!   r…   Ã  s    z&URL [{}] response: {}, headers: {{{}}}z
, data: {}©r   r   r   r   r   )r"   r   rÇ   r	   r-   rH   rI   r3   rQ   r‚   rˆ   rY   rM   rt   r.   rl   r   r   r¹   rº   r   ÚDatetimeAwareJSONDecoderÚ
isinstanceÚdictÚlistr¤   r4   r   r   )r   r—   r   r'   r:   rÎ   r=   Úsorted_header_strr)   Údecoded_bodyr   r   Ú	json_bodyÚ	debug_msgÚbody_to_logr    )r   rk   r!   Úreadurl’  sj   ÿüÿ	
ÿ

ÿ
ÿ
ûrä   Ú	localhostÚsocket_pathÚhttp_methodÚ	http_pathÚhttp_hostnamec                 C   sî   t   t jt j¡}| | ¡ tj |¡}||_z| ||¡ | 	¡ }| 
¡ jddd�}W | ¡  | ¡  n	| ¡  | ¡  w i }g }	d|j dd¡v rjtj|tjd�}
t|
tƒrZ|
}nt|
tƒrb|
}	nt dt|
ƒ¡ t|jt|jƒ|||	d	�S )
NrÑ   rÒ   rÓ   rÕ   rÖ   rÁ   r×   rÙ   rÚ   )r9   ÚAF_UNIXÚSOCK_STREAMÚconnectr   ÚclientÚHTTPConnectionÚsockr	   Úgetresponserj   rˆ   r°   r   rM   r¹   rº   r   rÛ   rÜ   rÝ   rÞ   r3   r¤   r4   r   Ústatusra   )ræ   rç   rè   ré   rï   Úconnrk   Úoutr   r   rá   r    r    r!   Úunix_socket_requestÛ  s8   

ÿ


ûrô   rX   )NN)rå   )=Úemail.messageÚemailÚhttp.clientr   r¥   r¹   ÚloggingrÆ   rK   r9   Útypingr   r   r   r   r   r   Úurllibr   r	   Úurllib.parser
   r   Úuaclientr   r   r   r   rJ   ÚPROXY_VALIDATION_APT_HTTP_URLÚPROXY_VALIDATION_APT_HTTPS_URLÚPROXY_VALIDATION_SNAP_HTTP_URLÚPROXY_VALIDATION_SNAP_HTTPS_URLÚ	getLoggerÚreplace_top_level_logger_nameÚ__name__r3   r¬   r4   Úbytesr   r   Úboolr"   rB   rS   rW   rY   ÚmessageÚMessagera   r-   rl   rt   r~   r.   rm   r¿   rÍ   rä   rô   r    r    r    r!   Ú<module>   sê     ýþ
ûþÿÿÿ
þ2ÿÿ
þ1þÿþ
ýýÿþý
ü_ÿÿÿ

þ6úÿþ
ýüûú
ùMüÿþýüû