
    -ek                        d Z ddlmZ ddlZ ej        e          ZddlmZm	Z	 erddl
m
Z
 ddlmZ dZddZddZddZddZdS ) zc Provide some utility functions useful for implementing different
components in ``bokeh.server``.

    )annotationsN)TYPE_CHECKINGSequence)socket)netutil)bind_socketscheck_allowlistcreate_hosts_allowlist
match_hostaddress
str | Noneportintreturntuple[list[socket], int]c                    t          j        |pd|           }t          |          sJ d |D             }t          |          dk    s
J d            |                                }|r||k    sJ ||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                B    h | ]}|                                 d          S )   )getsockname).0ss     1lib/python3.11/site-packages/bokeh/server/util.py	<setcomp>zbind_sockets.<locals>.<setcomp>F   s%    ,,,AQ]]__Q,,,    r   zMultiple ports assigned??)r   r   lenpop)r   r   ssportsactual_ports        r   r   r   0   s    ( 
	491g	>	>	>Br77NNN,,,,,Eu::???7???))++K #d""""{?r   hoststr	allowlistSequence[str]boolc                X     d vr dz     |v rdS t           f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  8   K   | ]}t          |          V  d S )N)r   )r   patternr    s     r   	<genexpr>z"check_allowlist.<locals>.<genexpr>e   s-      BBWz$((BBBBBBr   )any)r    r"   s   ` r   r	   r	   M   sJ    $ $e|ytBBBB	BBBBBBr   	host_listSequence[str] | None
int | None	list[str]c                   | sdt          |          z   gS g }| D ]&}d|v rt                              d|           |dk    r|                    |           >|                    d          }t          |          dk    r4|d         dk    rt          d          |                    |d	z              t          |          d
k    ri	 t          |d                    n # t          $ r t          d|z            w xY w|d         dk    rt          d          |                    |           t          d|z            |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    partss        r   r
   r
   g   ss   >  *s4yy())E > >$;;KK78<> > > 3;; LL

3u::??Qx2~~ !3444LLe$$$$ZZ1__JE!H J J J !AD!HIIIJQx2~~ !3444LL5<===Ls   CC;r)   c                   d}d| v r|                      dd          \  } }d}d|v r!|                     dd          \  }}|dk    rd}|||k    rdS |                     d          }|                    d          }t          |          t          |          k    rdS t          ||          D ]\  }}||k    s|dk    r dS d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   r1   F.T)rsplitr7   r   zip)r    r)   	host_portpattern_port
host_partspattern_partshps           r   r   r      s    d !I
d{{++c1--i#L
g~~ 'sA 6 63LI$=$=uCJMM#&&M
=C
OO++uJ..  166Q#XX554r   )r   r   r   r   r   r   )r    r!   r"   r#   r   r$   )r,   r-   r   r.   r   r/   )r    r!   r)   r!   r   r$   )__doc__
__future__r   logging	getLogger__name__r4   typingr   r   r   tornador   __all__r   r	   r
   r    r   r   <module>rN      s     # " " " " " g!! + * * * * * * *          :C C C C4= = = =~J J J J J Jr   