U
    g%U                     @  s  U d dl m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
Z	d dlZ	d dlmZ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 d	d
lmZ d	dlmZ d	dlm Z m!Z!m"Z"m#Z#m$Z$ d	dl%m&Z&m'Z' dZ(ddddZ)G dd dZ*i Z+dd Z,G dd dej-Z.G dd dej/Z0G dd dZ1ej2e1ddZ3ej2e1ddZ4G d d! d!ej5Z6ej7re8ee8 B ej9B dB Z:ej;e0e1ge<f Z=e> Z?d"e@d#< dS )$    )annotationsN)IterableMapping)Message)
HTTPStatus   )make_ssl_contextwrap_request_errors)NoSupportingHandlersRequestErrorTransportErrorUnsupportedRequest   )NoneType)YoutubeDLCookieJar)bug_reports_messageclasspropertydeprecation_warningerror_to_strupdate_url_query)HTTPHeaderDictnormalize_url   ztype[RequestHandler]handlersc                    s,   t dd  D stdd fdd}|S )Nc                 s  s   | ]}t |tV  qd S N)
issubclassRequestHandler).0handler r    </tmp/pip-unpacked-wheel-q5ljy6pj/yt_dlp/networking/common.py	<genexpr>&   s     z&register_preference.<locals>.<genexpr>
Preference
preferencec                   s&   t   fdd}t| |S )Nc                   s"    rt |  r| f||S dS )Nr   )
isinstance)r   argskwargs)r   r%   r    r!   inner)   s    z1register_preference.<locals>.outer.<locals>.inner)	functoolswraps_RH_PREFERENCESadd)r%   r)   r   r$   r!   outer(   s    
z"register_preference.<locals>.outer)allAssertionError)r   r.   r    r   r!   register_preference%   s    r1   c                   @  sX   e Zd ZdZdddZdd Zddd	d
ZdddddZdd ZdddddZ	dS )RequestDirectora  RequestDirector class

    Helper class that, when given a request, forward it to a RequestHandler that supports it.

    Preference functions in the form of func(handler, request) -> int
    can be registered into the `preferences` set. These are used to sort handlers
    in order of preference.

    @param logger: Logger instance.
    @param verbose: Print debug request information to stdout.
    Fc                 C  s   i | _ t | _|| _|| _d S r   )r   setpreferencesloggerverbose)selfr5   r6   r    r    r!   __init__@   s    zRequestDirector.__init__c                 C  s&   | j  D ]}|  q
| j   d S r   )r   valuescloseclearr7   r   r    r    r!   r:   F   s    
zRequestDirector.closer   r   c                 C  s"   t |tstd|| j|j< dS )zKAdd a handler. If a handler of the same RH_KEY exists, it will overwrite itz handler must be a RequestHandlerN)r&   r   r0   r   RH_KEYr<   r    r    r!   add_handlerK   s    zRequestDirector.add_handlerRequestzlist[RequestHandler]requestreturnc              	     sT    fddj  D }dddd | D  tj  |jddS )	z-Sorts handlers by preference, given a requestc                   s(   i | ]   t  fd djD qS )c                 3  s   | ]}| V  qd S r   r    )r   pref)rB   rhr    r!   r"   S   s     z;RequestDirector._get_handlers.<locals>.<dictcomp>.<genexpr>)sumr4   )r   rB   r7   )rE   r!   
<dictcomp>R   s    z1RequestDirector._get_handlers.<locals>.<dictcomp>z(Handler preferences for this request: {}, c                 s  s"   | ]\}}|j  d | V  qdS )=N)RH_NAME)r   rE   rD   r    r    r!   r"   V   s    z0RequestDirector._get_handlers.<locals>.<genexpr>T)keyreverse)r   r9   _print_verboseformatjoinitemssortedget)r7   rB   r4   r    rG   r!   _get_handlersP   s    zRequestDirector._get_handlersc                 C  s   | j r| jd|  d S )Nz
director: )r6   r5   stdout)r7   msgr    r    r!   rN   Z   s    zRequestDirector._print_verboseResponsec                 C  sf  | j stdt|tstg }g }| |D ]&}| d|j d z|| W nR t	k
r } z4| d|j dt
| d || W Y q.W 5 d}~X Y nX | d|j d z||}W nr tk
r    Y n^ tk
r> } z>| jjd	|j d
t
| t  dd || W Y q.W 5 d}~X Y nX t|tsPt|  S t||dS )zA
        Passes a request onto a suitable RequestHandler
        zNo request handlers configuredzChecking if "z" supports this request."z&" cannot handle this request (reason: )NzSending request via "[z] Unexpected error: F)Zis_error)r   r   r&   r@   r0   rT   rN   rK   validater   r   appendsend	Exceptionr5   errorr   rW   r
   )r7   rB   Zunexpected_errorsZunsupported_errorsr   eresponser    r    r!   r]   ^   s<    

zRequestDirector.sendN)F)
__name__
__module____qualname____doc__r8   r:   r?   rT   rN   r]   r    r    r    r!   r2   3   s   

r2   c                 C  sB   t | tst|  d| jtks4td| j d| t| j< | S )zRegister a RequestHandler classz% must be a subclass of RequestHandlerzRequestHandler z already registered)r   r   r0   r>   _REQUEST_HANDLERSr=   r    r    r!   register_rh   s    
rg   c                   @  s   e Zd Ze Ze ZdS )FeaturesN)rb   rc   rd   enumauto	ALL_PROXYNO_PROXYr    r    r    r!   rh      s   rh   c                      s  e Zd ZdZdZdZdZddddddddddd
ddd	d
ddddddd
 fddZd6ddZdd Z	dd Z
dd Zdd ZddddZdd Zd d! Zd"d# Zeddd$d%Zedd&d'd(d)Zejddd*d+Zd,d- Zed.d/ Zed0d1 Zd2d3 Zd4d5 Z  ZS )7r   a  Request Handler class

    Request handlers are class that, given a Request,
    process the request from start to finish and return a Response.

    Concrete subclasses need to redefine the _send(request) method,
    which handles the underlying request logic and returns a Response.

    RH_NAME class variable may contain a display name for the RequestHandler.
    By default, this is generated from the class name.

    The concrete request handler MUST have "RH" as the suffix in the class name.

    All exceptions raised by a RequestHandler should be an instance of RequestError.
    Any other exception raised will be treated as a handler issue.

    If a Request is not supported by the handler, an UnsupportedRequest
    should be raised with a reason.

    By default, some checks are done on the request in _validate() based on the following class variables:
    - `_SUPPORTED_URL_SCHEMES`: a tuple of supported url schemes.
        Any Request with an url scheme not in this list will raise an UnsupportedRequest.

    - `_SUPPORTED_PROXY_SCHEMES`: a tuple of support proxy url schemes. Any Request that contains
        a proxy url with an url scheme not in this list will raise an UnsupportedRequest.

    - `_SUPPORTED_FEATURES`: a tuple of supported features, as defined in Features enum.

    The above may be set to None to disable the checks.

    Parameters:
    @param logger: logger instance
    @param headers: HTTP Headers to include when sending requests.
    @param cookiejar: Cookiejar to use for requests.
    @param timeout: Socket timeout to use when sending requests.
    @param proxies: Proxies to use for sending requests.
    @param source_address: Client-side IP address to bind to for requests.
    @param verbose: Print debug request and traffic information to stdout.
    @param prefer_system_certs: Whether to prefer system certificates over other means (e.g. certifi).
    @param client_cert: SSL client certificate configuration.
            dict with {client_certificate, client_certificate_key, client_certificate_password}
    @param verify: Verify SSL certificates
    @param legacy_ssl_support: Enable legacy SSL options such as legacy server connect and older cipher support.

    Some configuration options may be available for individual Requests too. In this case,
    either the Request configuration option takes precedence or they are merged.

    Requests may have additional optional parameters defined as extensions.
     RequestHandler subclasses may choose to support custom extensions.

    If an extension is supported, subclasses should extend _check_extensions(extensions)
    to pop and validate the extension.
    - Extensions left in `extensions` are treated as unsupported and UnsupportedRequest will be raised.

    The following extensions are defined for RequestHandler:
    - `cookiejar`: Cookiejar to use for this request.
    - `timeout`: socket timeout to use for this request.
    - `legacy_ssl`: Enable legacy SSL options for this request. See legacy_ssl_support.
    To enable these, add extensions.pop('<extension>', None) to _check_extensions

    Apart from the url protocol, proxies dict may contain the following keys:
    - `all`: proxy to use for all protocols. Used as a fallback if no proxy is set for a specific protocol.
    - `no`: comma seperated list of hostnames (optionally with port) to not use a proxy for.
    Note: a RequestHandler may not support these, as defined in `_SUPPORTED_FEATURES`.

    r    NFT)
headers	cookiejartimeoutproxiessource_addressr6   prefer_system_certsclient_certverifylegacy_ssl_supportr   r   zfloat | int | Nonedict | None
str | Noneboolzdict[str, str | None] | Nonec                  sr   || _ |pi | _|d k	r|nt | _t|p,t| _|p8i | _|| _|| _	|| _
|	pTi | _|
| _|| _t   d S r   )Z_loggerrm   r   rn   floatDEFAULT_TIMEOUTro   rp   rq   r6   rr   _client_certrt   ru   superr8   )r7   r5   rm   rn   ro   rp   rq   r6   rr   rs   rt   ru   _	__class__r    r!   r8      s    


zRequestHandler.__init__c                 C  s,   t f | j|d k	r|n| j| j d| jS )N)rt   Zlegacy_supportZuse_certifi)r   rt   ru   rr   r{   )r7   ru   r    r    r!   _make_sslcontext   s    zRequestHandler._make_sslcontextc                 C  s   t | j|S r   )r   rm   )r7   Zrequest_headersr    r    r!   _merge_headers  s    zRequestHandler._merge_headersc                 C  s   t |jdp| jS )Nro   )ry   
extensionsrS   ro   r7   rB   r    r    r!   _calculate_timeout  s    z!RequestHandler._calculate_timeoutc                 C  s   |j d}|d kr| jS |S )Nrn   )r   rS   rn   )r7   rB   rn   r    r    r!   _get_cookiejar	  s    zRequestHandler._get_cookiejarc                 C  s   |j p
| j  S r   )rp   copyr   r    r    r!   _get_proxies  s    zRequestHandler._get_proxiesr@   )rB   c                 C  s<   t j|jj }| jd k	r8|| jkr8td| d|S )NzUnsupported url scheme: "rX   )urllibparseurlparseurlschemelower_SUPPORTED_URL_SCHEMESr   )r7   rB   r   r    r    r!   _check_url_scheme  s    z RequestHandler._check_url_schemec                 C  s"  |  D ]\}}|d krq|dkrD| jd k	rtj| jkrtdq|dkrj| jd k	rjtj| jkrjtd| jd k	r|| jdkrq| jd krqz(tj	
|d d krtd| dW n6 tk
r } ztd| d	| W 5 d }~X Y nX tj|j }|| jkrtd
| dqd S )Nnoz"no" proxy is not supportedr/   z"all" proxy is not supportedr   zProxy "z" missing schemezInvalid proxy url "z": zUnsupported proxy type: "rX   )r/   )rQ   _SUPPORTED_FEATURESrh   rl   r   rk   r   _SUPPORTED_PROXY_SCHEMESr   rB   _parse_proxy
ValueErrorr   r   r   r   )r7   rp   	proxy_key	proxy_urlr`   r   r    r    r!   _check_proxies  s4    

&
zRequestHandler._check_proxiesc                 C  sN   t |dttfstt |dtttfs2tt |dttfsJtdS )zKCheck extensions for unsupported extensions. Subclasses should extend this.rn   ro   Z
legacy_sslN)r&   rS   r   r   r0   ry   intrx   )r7   r   r    r    r!   _check_extensions;  s    z RequestHandler._check_extensionsc                 C  sP   |  | | |jp| j |j }| | |rLtdd|  d S )NzUnsupported extensions: rI   )	r   r   rp   r   r   r   r   rP   keys)r7   rB   r   r    r    r!   	_validateA  s    


zRequestHandler._validatec                 C  s    t |tstd| | d S NzExpected an instance of Request)r&   r@   	TypeErrorr   r   r    r    r!   r[   J  s    
zRequestHandler.validaterW   rA   c                 C  s   t |tstd| |S r   )r&   r@   r   _sendr   r    r    r!   r]   P  s    
zRequestHandler.sendc                 C  s   dS )z>Handle a request from start to finish. Redefine in subclasses.Nr    r   r    r    r!   r   V  s    zRequestHandler._sendc                 C  s   d S r   r    r7   r    r    r!   r:   [  s    zRequestHandler.closec                 C  s   | j d d S )N)rb   clsr    r    r!   rK   ^  s    zRequestHandler.RH_NAMEc                 C  s"   | j dstd| j d d S )NZRHz-RequestHandler class names must end with "RH"r   )rb   endswithr0   r   r    r    r!   r>   b  s    zRequestHandler.RH_KEYc                 C  s   | S r   r    r   r    r    r!   	__enter__g  s    zRequestHandler.__enter__c                 G  s   |    d S r   )r:   )r7   r'   r    r    r!   __exit__j  s    zRequestHandler.__exit__)N)rb   rc   rd   re   r   r   r   r8   r   r   r   r   r   r   r   r   r   r	   r[   r]   abcabstractmethodr   r:   r   rK   r>   r   r   __classcell__r    r    r~   r!   r      sJ   C(
%	

r   c                	   @  s   e Zd ZdZd ddddddddd	d
Zedd Zejdd Zedd Zejdd Zedd Z	e	jddddZ	eddddZ
e
jddddZ
d!ddZdd ZdS )"r@   a  
    Represents a request to be made.
    Partially backwards-compatible with urllib.request.Request.

    @param url: url to send. Will be sanitized.
    @param data: payload data to send. Must be bytes, iterable of bytes, a file-like object or None
    @param headers: headers to send.
    @param proxies: proxy dict mapping of proto:proxy to use for the request and any redirects.
    @param query: URL query parameters to update the url with.
    @param method: HTTP method to use. If no method specified, will use POST if payload data is present else GET
    @param extensions: Dictionary of Request extensions to add, as supported by handlers.
    NstrRequestDataztyping.Mapping | Nonerv   rw   )r   datarm   rp   querymethodr   c                 C  sP   t  | _d | _|rt||}|| _|| _|r2|| _|| _|p>i | _|pHi | _	d S r   )
r   _headers_datar   r   r   rm   r   rp   r   )r7   r   r   rm   rp   r   r   r   r    r    r!   r8   |  s    

zRequest.__init__c                 C  s   | j S r   )_urlr   r    r    r!   r     s    zRequest.urlc                 C  s4   t |tstdn|dr&d| }t|| _d S )Nzurl must be a stringz//zhttp:)r&   r   r   
startswithr   r   )r7   r   r    r    r!   r     s
    


c                 C  s   | j p| jd k	rdS dS )NPOSTGET)_methodr   r   r    r    r!   r     s    zRequest.methodc                 C  s2   |d krd | _ nt|tr&| | _ ntdd S )Nzmethod must be a string)r   r&   r   upperr   )r7   r   r    r    r!   r     s
    
c                 C  s   | j S r   )r   r   r    r    r!   r     s    zRequest.data)r   c                 C  s   |d k	r0t |ttjtfr(t |ttfr0td|| jkrR| jd krR| j	
dd  || jkrz| jd k	rt| j	
dd  || _| jd kr| j	
dd  d| j	kr| jd k	rd| j	d< d S )Nz<data must be bytes, iterable of bytes, or a file-like objectzContent-LengthzContent-Typez!application/x-www-form-urlencoded)r&   bytesioIOBaser   r   r   r   r   rm   pop)r7   r   r    r    r!   r     s     


r   )rC   c                 C  s   | j S r   )r   r   r    r    r!   rm     s    zRequest.headersr   )new_headersc                 C  s4   t |tr|| _nt |tr(t|| _ntddS )zVReplaces headers of the request. If not a HTTPHeaderDict, it will be converted to one.zheaders must be a mappingN)r&   r   r   r   r   )r7   r   r    r    r!   rm     s
    

c                 C  sN   |d k	r|n| j | _ | j|p i  | j|p0i  t|p>| j|pDi | _d S r   )r   rm   updater   r   r   )r7   r   r   rm   r   r   r    r    r!   r     s    zRequest.updatec                 C  s4   | j | jt| jt| j| jt| j| jdS )N)r   rm   rp   r   r   r   )	r   r   r   deepcopyrm   rp   r   r   r   r   r    r    r!   r     s    


zRequest.copy)NNNNNN)NNNNN)rb   rc   rd   re   r8   propertyr   setterr   r   rm   r   r   r    r    r    r!   r@   n  s4         




	
r@   HEAD)r   PUTc                      s   e Zd ZdZd"dddddd	d
ddZdd Zd#dddddZ fddZd$ddZe	dd Z
dd Zdd Zdd Zd%d d!Z  ZS )&rW   aR  
    Base class for HTTP response adapters.

    By default, it provides a basic wrapper for a file-like response object.

    Interface partially backwards-compatible with addinfourl and http.client.HTTPResponse.

    @param fp: Original, file-like, response.
    @param url: URL that this is a response of.
    @param headers: response headers.
    @param status: Response HTTP status code. Default is 200 OK.
    @param reason: HTTP status reason. Will use built-in reasons based on status code if not provided.
    @param extensions: Dictionary of handler-specific response extensions.
       Nz	io.IOBaser   zMapping[str, str]r   rw   rv   )fpr   rm   statusreasonr   c           	      C  sx   || _ t | _| D ]\}}| j|| q|| _|| _z|pHt|j| _	W n t
k
rh   d | _	Y nX |ppi | _d S r   )r   r   rm   rQ   
add_headerr   r   r   phraser   r   r   )	r7   r   r   rm   r   r   r   namevaluer    r    r!   r8     s    
zResponse.__init__c                 C  s
   | j  S r   )r   readabler   r    r    r!   r     s    zResponse.readablez
int | Noner   )amtrC   c              
   C  sB   z| j |W S  tk
r< } zt|d|W 5 d }~X Y nX d S )N)cause)r   readr^   r   )r7   r   r`   r    r    r!   r     s    zResponse.readc                   s   | j   t  S r   )r   r:   r|   r   r~   r    r!   r:     s    
zResponse.closec                 C  s2   | j |}|s|S | dkr(|d S d|S )zcGet header for name.
        If there are multiple matching headers, return all seperated by comma.z
Set-Cookier   rI   )rm   get_alltitlerP   )r7   r   defaultrm   r    r    r!   
get_header!  s    zResponse.get_headerc                 C  s   t ddd | jS )Nz0Response.code is deprecated, use Response.statusr   
stacklevelr   r   r   r    r    r!   code.  s    zResponse.codec                 C  s   t ddd | jS )Nz5Response.getcode() is deprecated, use Response.statusr   r   r   r   r    r    r!   getcode3  s    zResponse.getcodec                 C  s   t ddd | jS )Nz1Response.geturl() is deprecated, use Response.urlr   r   )r   r   r   r    r    r!   geturl7  s    zResponse.geturlc                 C  s   t ddd | jS )Nz3Response.info() is deprecated, use Response.headersr   r   )r   rm   r   r    r    r!   info;  s    zResponse.infoc                 C  s   t ddd | ||S )Nz;Response.getheader() is deprecated, use Response.get_headerr   r   )r   r   )r7   r   r   r    r    r!   	getheader?  s    zResponse.getheader)r   NN)N)N)N)rb   rc   rd   re   r8   r   r   r:   r   r   r   r   r   r   r   r   r    r    r~   r!   rW     s      

rW   zset[Preference]r,   )A
__future__r   r   r   ri   r*   r   typingurllib.parser   urllib.requesturllib.responsecollections.abcr   r   email.messager   httpr   Z_helperr   r	   
exceptionsr
   r   r   r   Zcompat.typesr   cookiesr   utilsr   r   r   r   r   Zutils.networkingr   r   rz   r1   r2   rf   rg   Enumrh   ABCr   r@   partialZHEADRequestZ
PUTRequestr   rW   TYPE_CHECKINGr   IOr   Callabler   r#   r3   r,   __annotations__r    r    r    r!   <module>   sF    R ZzX