U
    lHJe-                  	   @   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!ee"dddZ#ee
e ee
e dddZ$i a%e
e e
e ddddZ&eeef dddZ'd.ej(e
e e ddd Z)d!d" Z*d#d$ Z+d/ej(e
e e
e e d%d&d'Z,e
e dd(d)Z-di ddd*fee
e. eeef e
e e
e e"e!d+d,d-Z/dS )0    N)AnyDictList
NamedTupleOptional)errorrequest)ParseResulturlparse)defaults
exceptionsutil)z169.254.169.254Z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   sX   zt | }W n tk
r"   Y dS X |jdkr2dS z
|j W n tk
rR   Y dS X dS )NF)httpshttpT)r
   
ValueErrorschemeZport)r   Z
parsed_url r   8/usr/lib/python3/dist-packages/uaclient/http/__init__.pyis_service_url(   s    

r   )protocolproxytest_urlr   c                 C   sr  |sd S t |stj|dtj|dd}| dkrt|jdkrzt||d}W n tjk
rh    Y nn tj	k
r~    Y nX tj
k
r    Y nB tk
r } z$td||t| tj|dW 5 d }~X Y nX |jdkr|S tj|dt| |i}t|}z|| |W S  tjtjfk
rl } z,td||t|d	t| tj|dW 5 d }~X Y nX d S )
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   ZProxyInvalidUrlr   Requestr
   r   _readurl_pycurl_https_in_httpsPycurlRequiredErrorProxyAuthenticationFailedPycurlCACertificatesError	ExceptionLOGr   strZProxyNotWorkingErrorr   ProxyHandlerbuild_openeropensockettimeoutURLErrorgetattr)r   r   r    reqZresponseeproxy_handleropenerr   r   r   validate_proxy9   sL    


r:   )
http_proxyr$   r   c                 C   s   i }| r| |d< |r||d< d tt}dD ]6}tj|}|r.d tt|dtt}q.t	
d| |tjd< |tjd< |rt|}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: %sr=   r>   zSetting global proxy dictextra)r?   N)joinsortedUA_NO_PROXY_URLSosenvirongetsetsplitunionr-   debugr   r/   r0   Zinstall_opener_global_proxy_dict)r;   r$   Z
proxy_dictr=   Zenv_varZproxy_valuer8   r9   r   r   r   configure_web_proxyn   s.    




rK   )r   c                   C   s   t S )N)rJ   r   r   r   r   get_configured_web_proxy   s    rL   )r6   r3   r   c              
   C   s   zt j| |d}W nZ tjk
r: } z|}W 5 d }~X Y n4 tjk
rl } ztj|| jdW 5 d }~X Y nX | 	d}dd |j
 D }t|j||dS )Nr3   r   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   Zurlopenr   Z	HTTPErrorr4   r   ZUrlErrorZfull_urlreaddecoder   itemsr   r   )r6   r3   respr7   r   r   r   r   r   _readurl_urllib   s    "rZ   c                 C   sJ   t |}t| }|jdko8t|j o8|dk	o8|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   Zproxy_bypassZhostnamer-   rI   )r$   Z
target_urlZparsed_target_urlparsed_https_proxyZretr   r   r   should_use_pycurl   s    
r]   c                 C   s|   d }d }t | jdkr | jd }t | jdkr8| jd }||krV|rVd|krVt n"||krltj|dntj| dd S )Nr      zHTTP code 407 from proxyrN   )r7   )lenargsr   r*   r+   ZPycurlError)r   r   authentication_error_codeca_certificates_error_coder   msgr   r   r   _handle_pycurl_error   s     


rd   )r6   r3   r$   r   c              
      s  zdd l }W n tk
r(   t Y nX | }|   }|dkrV||jd nT|dkrn||j	d n<|dkr||j
d | jr||j| j ntd|||j|   dd |  D }t|dkr||j| ||jd ||jtj |r||j| |rXt|}|r6| nd }||j| ||jd	 n
td
 t  }||j!| i   fdd}	||j"|	 z|#  W n> |j$k
r }
 zt%|
|  |j&|j'd W 5 d }
~
X Y nX 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)rQ   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| krd S | dd\}}|  }| }| |< d S )Nz
iso-8859-1:r^   )rW   rG   striprP   )Zheader_lineZname_rawZ	value_rawri   valuer   r   r   save_header%  s    
z3_readurl_pycurl_https_in_https.<locals>.save_header)r   ra   rb   rO   rU   )/pycurlImportErrorr   r)   ZCurlZ
get_methodupperZsetoptZHTTPGETZNOBODYrf   dataZCOPYPOSTFIELDSr   rh   ZURLZget_full_urlZheader_itemsr_   Z
HTTPHEADERZFOLLOWLOCATIONZCAINFOr   ZSSL_CERTS_PATHZTIMEOUTr[   ZgeturlZPROXYZ	PROXYTYPEr-   ZwarningioBytesIOZ	WRITEDATAZHEADERFUNCTIONZperformr   rd   ZE_RECV_ERRORZE_SSL_CACERT_BADFILEintZgetinfoZRESPONSE_CODEgetvaluerW   closer   )r6   r3   r$   rr   cr"   Zheader_str_listr\   Zbody_outputrq   r7   r   r   r   rp   r   r(      st    
	r(   c                 C   s"   | st  d} | rt| S d S )Nr   )r   Z
getproxiesrE   r
   r#   r   r   r   r[   G  s    r[   T)r   ru   r   r"   r3   log_response_bodyr   c              
      sb  |r|sd}t j| | |d}d fddt D }td|pHd| ||rZ|dnd  t 	d	}t
|| rt|||d
nt||di }	g }
dj	ddkrtjjtjd}t|tr|}	nt|tr|}
dfddtjD }d|pd| |}|r@j}|	r(|	}n
|
r2|
}|d|7 }t| tjjj|	|
dS )Nrf   )ru   r   r"   z, c                    s   g | ]}d  | | qS z
'{}': '{}'rg   rQ   rR   rp   r   r   rk   Z  s     zreadurl.<locals>.<listcomp>z'URL [{}]: {}, headers: {{{}}}, data: {}re   rO   r   )r3   r$   rM   zapplication/jsonzcontent-type )clsc                    s   g | ]}d  | j| qS r}   )rh   r   r~   )rY   r   r   rk   w  s     z&URL [{}] response: {}, headers: {{{}}}z
, data: {})r   r   r   r   r   )r   r'   r@   rA   r-   rI   rh   rW   rL   rE   r]   r(   rZ   r   jsonloadsr   r   ZDatetimeAwareJSONDecoder
isinstancedictlistr   r   )r   ru   r   r"   r3   r|   r6   Zsorted_header_strr$   r   r   Z	json_bodyZ	debug_msgZbody_to_logr   )r   rY   r   readurlM  sj    	
  

  
r   )N)NN)0rv   r   ZloggingrC   r2   typingr   r   r   r   r   Zurllibr   r   Zurllib.parser	   r
   Zuaclientr   r   r   rB   ZPROXY_VALIDATION_APT_HTTP_URLZPROXY_VALIDATION_APT_HTTPS_URLZPROXY_VALIDATION_SNAP_HTTP_URLZPROXY_VALIDATION_SNAP_HTTPS_URLZ	getLoggerZreplace_top_level_logger_name__name__r-   rx   r.   r   r   boolr   r:   rJ   rK   rL   r'   rZ   r]   rd   r(   r[   bytesr   r   r   r   r   <module>   s   
  2 1    _
