o
    ϴfm-                     @   s  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
 d dlmZmZ d dlmZmZ d dl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'	d3d!ej(d"e
e de fd#d$Z)d%d& Z*d'd( Z+		d4d!ej(d"e
e de
e de fd)d*Z,de
e fd+d,Z-di ddd-fded.e
e. deeef d/e
e d"e
e d0e"de!fd1d2Z/dS )5    N)AnyDictList
NamedTupleOptional)errorrequest)ParseResulturlparse)defaults
exceptions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_proxy9   sT   
	

r@   
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: %srC   rD   zSetting global proxy dictextra)rE   N)joinsortedUA_NO_PROXY_URLSosenvirongetsetsplitunionr1   debugr   r4   r5   install_opener_global_proxy_dict)rA   r'   
proxy_dictrC   env_varproxy_valuer>   r?   r   r   r   configure_web_proxyn   s0   




rU   c                   C   s   t S N)rQ   r   r   r   r   get_configured_web_proxy   s   rW   r;   r8   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 | d}dd |j D }t|j||dS )Nr8   )causer   utf-8c                 S   s   i | ]	\}}|  |qS r   )lower).0kvr   r   r   
<dictcomp>   s    z#_readurl_urllib.<locals>.<dictcomp>r   r   r   )r   urlopenr   	HTTPErrorr9   r1   	exceptionr2   r)   r   ConnectivityErrorfull_urlreaddecoder   itemsr   r   )r;   r8   respr=   r   r   r   r   r   _readurl_urllib   s"   rj   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hostnamer1   rO   )r'   
target_urlparsed_target_urlparsed_https_proxyretr   r   r   should_use_pycurl   s   
rr   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   r.   r/   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*}|+ ,d}|-  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:rs   )rg   rM   stripr[   )header_linename_raw	value_rawr   valuer   r   r   save_header"  s   
z3_readurl_pycurl_https_in_https.<locals>.save_header)r   ry   rz   rZ   r`   )/pycurlImportErrorr   r-   Curl
get_methoduppersetoptHTTPGETNOBODYr~   dataCOPYPOSTFIELDSr   r   URLget_full_urlheader_itemsrv   
HTTPHEADERFOLLOWLOCATIONCAINFOr   SSL_CERTS_PATHTIMEOUTrk   geturlPROXY	PROXYTYPEr1   warningioBytesIO	WRITEDATAHEADERFUNCTIONperformr   r|   E_RECV_ERRORE_SSL_CACERT_BADFILEintgetinfoRESPONSE_CODEgetvaluerg   closer   )r;   r8   r'   r   cr%   header_str_listrp   body_outputr   r=   r   r   r   r   r   r,      s|   
	r,   c                 C   s"   | s	t  d} | rt| S d S )Nr   )r   
getproxiesrK   r
   r&   r   r   r   rk   D  s   rk   Tr   r%   log_response_bodyc              
      sn  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i }	g }
djddv rytjjtjd}t|trr|}	nt|try|}
dfddtjD }d	|pd| |}|rj}|	r|	}n|
r|
}|d	|7 }t| tjjj|	|
dS )Nru   r~   )r   r   r%   z, c                    s   g | ]
}d  | | qS z
'{}': '{}'r   r\   r]   r   r   r   r   Z  s    zreadurl.<locals>.<listcomp>z'URL [{}]: {}, headers: {{{}}}, data: {}r}   rZ   r   )r8   r'   rX   zapplication/jsonzcontent-type )clsc                    s   g | ]}d  | j| qS r   )r   r   r   )ri   r   r   r   w  s    z&URL [{}] response: {}, headers: {{{}}}z
, data: {})r   r   r   r   r   )r    r   
InvalidUrlr   r+   rF   rG   r1   rO   r   rg   rW   rK   rr   r,   rj   r   jsonloadsr   r   DatetimeAwareJSONDecoder
isinstancedictlistr   r   )r   r   r   r%   r8   r   r;   sorted_header_strr'   r   r   	json_body	debug_msgbody_to_logr   )r   ri   r   readurlJ  sf   	




r   rV   )NN)0r   r   loggingrI   r7   typingr   r   r   r   r   urllibr   r   urllib.parser	   r
   uaclientr   r   r   rH   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__r1   r   r2   r   r   boolr    r@   rQ   rU   rW   r+   rj   rr   r|   r,   rk   bytesr   r   r   r   r   <module>   s    

2
1

_
