U
    /e                     @  s   d Z ddlmZ ddlZeeZddlmZm	Z	m
Z
mZ erJddlmZ ddlmZ dZdd	d
dddZddddddZdd	ddddZddddddZdS )zc Provide some utility functions useful for implementing different
components in ``bokeh.server``.

    )annotationsN)TYPE_CHECKINGListSequenceTuple)socket)netutil)bind_socketscheck_allowlistcreate_hosts_allowlist
match_hostz
str | NoneintzTuple[List[socket], int])addressportreturnc                 C  s`   t j|p
d| d}t|stdd |D }t|dks@td| }|rX||ksXt||fS )a   Bind a socket to a port on an address.

    Args:
        address (str) :
            An address to bind a port on, e.g. ``"localhost"``

        port (int) :
            A port number to bind.

            Pass 0 to have the OS automatically choose a free port.

    This function returns a 2-tuple with the new socket as the first element,
    and the port that was bound as the second. (Useful when passing 0 as a port
    number to bind any free port.)

    Returns:
        (socket, port)

    r   )r   r   c                 S  s   h | ]}|  d  qS )   )getsockname).0s r   5/tmp/pip-unpacked-wheel-f5fndrjf/bokeh/server/util.py	<setcomp>K   s     zbind_sockets.<locals>.<setcomp>r   zMultiple ports assigned??)r   r	   lenAssertionErrorpop)r   r   ssZportsactual_portr   r   r   r	   5   s    r	   strzSequence[str]bool)host	allowlistr   c                   s2   d kr d   |krdS t  fdd|D S )a   Check a given request host against a allowlist.

    Args:
        host (str) :
            A host string to compare against a allowlist.

            If the host does not specify a port, then ``":80"`` is implicitly
            assumed.

        allowlist (seq[str]) :
            A list of host patterns to match against

    Returns:
        ``True``, if ``host`` matches any pattern in ``allowlist``, otherwise
        ``False``

     ::80Tc                 3  s   | ]}t  |V  qd S )N)r   )r   patternr   r   r   	<genexpr>j   s     z"check_allowlist.<locals>.<genexpr>)any)r   r    r   r$   r   r
   R   s
    r
   zSequence[str] | Nonez	List[str])	host_listr   r   c              	   C  s   | sdt | gS g }| D ]}d|kr2td| |dkrF|| q|d}t|dkr|d dkrptd||d	  qt|d
krzt|d  W n  tk
r   td| Y nX |d dkrtd|| qtd| q|S )an  

    This allowlist can be used to restrict websocket or other connections to
    only those explicitly originating from approved hosts.

    Args:
        host_list (seq[str]) :
            A list of string `<name>` or `<name>:<port>` values to add to the
            allowlist.

            If no port is specified in a host string, then ``":80"``  is
            implicitly assumed.

        port (int) :
            If ``host_list`` is empty or ``None``, then the allowlist will
            be the single item list `` [ 'localhost:<port>' ]``

            If ``host_list`` is not empty, this parameter has no effect.

    Returns:
        list[str]

    Raises:
        ValueError, if host or port values are invalid

    Note:
        If any host in ``host_list`` contains a wildcard ``*`` a warning will
        be logged regarding permissive websocket connections.

    z
localhost:*zHost wildcard %r will allow connections originating from multiple (or possibly all) hostnames or IPs. Use non-wildcard values to restrict access explicitlyr!   r   r    zEmpty host valuer"      zInvalid port in host value: %szInvalid host value: %s)r   logwarningappendsplitr   
ValueErrorr   )r'   r   hostsr   partsr   r   r   r   l   s6    

r   )r   r#   r   c                 C  s   d}d| kr|  dd\} }d}d|krD| dd\}}|dkrDd}|dk	rX||krXdS | d}|d}t|t|krdS t||D ]"\}}||ks|dkrqq dS qdS )aa   Match a host string against a pattern

    Args:
        host (str)
            A hostname to compare to the given pattern

        pattern (str)
            A string representing a hostname pattern, possibly including
            wildcards for ip address octets or ports.

    This function will return ``True`` if the hostname matches the pattern,
    including any wildcards. If the pattern contains a port, the host string
    must also contain a matching port.

    Returns:
        bool

    Examples:

        >>> match_host('192.168.0.1:80', '192.168.0.1:80')
        True
        >>> match_host('192.168.0.1:80', '192.168.0.1')
        True
        >>> match_host('192.168.0.1:80', '192.168.0.1:8080')
        False
        >>> match_host('192.168.0.1', '192.168.0.2')
        False
        >>> match_host('192.168.0.1', '192.168.*.*')
        True
        >>> match_host('alice', 'alice')
        True
        >>> match_host('alice:80', 'alice')
        True
        >>> match_host('alice', 'bob')
        False
        >>> match_host('foo.example.com', 'foo.example.com.net')
        False
        >>> match_host('alice', '*')
        True
        >>> match_host('alice', '*:*')
        True
        >>> match_host('alice:80', '*')
        True
        >>> match_host('alice:80', '*:80')
        True
        >>> match_host('alice:8080', '*:80')
        False

    Nr!   r   r(   F.T)rsplitr.   r   zip)r   r#   	host_portZpattern_portZ
host_partspattern_partshpr   r   r   r      s&    2

r   )__doc__
__future__r   logging	getLogger__name__r+   typingr   r   r   r   r   Ztornador   __all__r	   r
   r   r   r   r   r   r   <module>   s   
?