o
    Kii;                     @   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| |rt|}|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 sw   Y  W d    W d S 1 sw   Y  W d S  tjy }
 z|
jdkrtj|d|
jdkrt  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 rtj|	tjd}t|try|}
nt|tr|}ntdt| dfddtjD }d	|pd| |}|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