
    g:                        d 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 ddl	m
Z
 ddlmZ ddlmZ 	 ddlZd Z G d d      Z G d d      Z y# e$ r 	 dd	lmZmZ ddlZej,                  j.                  Zej2                  j4                  ej2                  j6                  ej2                  j6                  ge_        ej2                  j:                  e_        d
 Zn# e$ r d ZY nw xY wY w xY w)z%Utilities to manage open connections.    N)suppress   )errors)
IS_WINDOWS)MakeFilec                     | j                         }t        j                  |t        j                        }t        j                  |t        j                  |t        j                  z         y)z4Mark the given socket fd as non-inheritable (POSIX).N)filenofcntlF_GETFDF_SETFD
FD_CLOEXEC)sockfd	old_flagss      (/opt/Tautulli/lib/cheroot/connections.pyprevent_socket_inheritancer   )   s@    [[]KKEMM2	By53C3C'CD    )windllWinErrorc                 N    t        | j                         dd      s
t               y)z6Mark the given socket fd as non-inheritable (Windows).r   r   N)_SetHandleInformationr	   r   r   s    r   r   r   $   s!    (1=j  >r   c                      y)ztStub inheritance prevention.

            Dummy function, since neither fcntl nor ctypes are available.
            N r   s    r   r   r      s    
 r   c                   H    e Zd ZdZd Zd Zed        Zd
dZd Z	d
dZ
d	 Zy)_ThreadsafeSelectora  Thread-safe wrapper around a DefaultSelector.

    There are 2 thread contexts in which it may be accessed:
      * the selector thread
      * one of the worker threads in workers/threadpool.py

    The expected read/write patterns are:
      * :py:func:`~iter`: selector thread
      * :py:meth:`register`: selector thread and threadpool,
        via :py:meth:`~cheroot.workers.threadpool.ThreadPool.put`
      * :py:meth:`unregister`: selector thread only

    Notably, this means :py:class:`_ThreadsafeSelector` never needs to worry
    that connections will be removed behind its back.

    The lock is held when iterating or modifying the selector but is not
    required when :py:meth:`select()ing <selectors.BaseSelector.select>` on it.
    c                 h    t        j                         | _        t        j                         | _        y N)	selectorsDefaultSelector	_selector	threadingLock_lockselfs    r   __init__z_ThreadsafeSelector.__init__D   s     "224^^%
r   c                     | j                   5  t        | j                  j                         xs i       cd d d        S # 1 sw Y   y xY wr   )r$   lenr!   get_mapr%   s    r   __len__z_ThreadsafeSelector.__len__H   s8    ZZ 	7t~~--/526	7 	7 	7s	   '>Ac              #      K   | j                   5  | j                  j                         xs i }|j                         D ]  \  }\  }}}}||f  	 ddd       y# 1 sw Y   yxY ww)z2Retrieve connections registered with the selector.N)r$   r!   r*   items)r&   mapping_sock_fdconns        r   connectionsz_ThreadsafeSelector.connectionsL   sg      ZZ 	&nn,,.4"G,3MMO &((Aw4o%&	& 	& 	&s   A'AA	A'A$ A'Nc                     | j                   5  | j                  j                  |||      cddd       S # 1 sw Y   yxY w)z'Register ``fileobj`` with the selector.N)r$   r!   register)r&   fileobjeventsdatas       r   r4   z_ThreadsafeSelector.registerT   s8    ZZ 	B>>**7FDA	B 	B 	Bs   4=c                 |    | j                   5  | j                  j                  |      cddd       S # 1 sw Y   yxY w)z)Unregister ``fileobj`` from the selector.N)r$   r!   
unregister)r&   r5   s     r   r9   z_ThreadsafeSelector.unregisterY   s0    ZZ 	6>>,,W5	6 	6 	6s   2;c                 H    d | j                   j                  |      D        S )zReturn socket fd and data pairs from selectors.select call.

        Returns entries ready to read in the form:
            (socket_file_descriptor, connection)
        c              3   R   K   | ]  \  }}|j                   |j                  f ! y wr   )r   r7   ).0keyr/   s      r   	<genexpr>z-_ThreadsafeSelector.select.<locals>.<genexpr>d   s)      
Q VVSXX
s   %'timeout)r!   select)r&   r@   s     r   rA   z_ThreadsafeSelector.select^   s&    
..///@
 	
r   c                 z    | j                   5  | j                  j                          ddd       y# 1 sw Y   yxY w)zClose the selector.N)r$   r!   closer%   s    r   rC   z_ThreadsafeSelector.closei   s.    ZZ 	#NN  "	# 	# 	#s   1:r   )__name__
__module____qualname____doc__r'   r+   propertyr2   r4   r9   rA   rC   r   r   r   r   r   0   s:    &&7 & &B
6
	
#r   r   c                   f    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zed        Zed        Zy)ConnectionManagerzClass which manages HTTPConnection objects.

    This is for connections which are being kept-alive for follow-up requests.
    c                     d| _         d| _        || _        t               | _        | j                  j                  |j                  j                         t        j                  |       y)zInitialize ConnectionManager object.

        Args:
            server (cheroot.server.HTTPServer): web server object
                that uses this ConnectionManager instance.
        Fr7   N)
_serving_stop_requestedserverr   r!   r4   socketr	   r   
EVENT_READ)r&   rO   s     r   r'   zConnectionManager.__init__u   sV     $,.MM  "  v 	  	
r   c                 *   t        j                          |_        |j                  j                         r| j                  j                  |       y| j                  j                  |j                  j                         t        j                  |       y)zPut idle connection into the ConnectionManager to be managed.

        :param conn: HTTP connection to be managed
        :type conn: cheroot.server.HTTPConnection
        rL   N)time	last_usedrfilehas_datarO   process_connr!   r4   rP   r	   r   rQ   )r&   r1   s     r   putzConnectionManager.put   sf      :: KK$$T*NN##""$i&:&: $ r   c                 
   | j                   j                  D cg c]'  \  }}|| j                  k7  r|j                  |k  r||f) }}}|D ]0  \  }}| j                   j	                  |       |j                          2 yc c}}w )aI  Expire least recently used connections.

        :param threshold: Connections that have not been used within this \
                          duration (in seconds), are considered expired and \
                          are closed and removed.
        :type threshold: float

        This should be called periodically.
        N)r!   r2   rO   rT   r9   rC   )r&   	thresholdr0   r1   timed_out_connectionss        r   _expirezConnectionManager._expire   s     $(>>#=#=!
$t{{"t~~	'A dO!
 !

 3 	MGTNN%%g.JJL	!
s   ,A?c                 p    d| _         | j                  r#t        j                  d       | j                  r"yy)z^Stop the selector loop in run() synchronously.

        May take up to half a second.
        Tg{Gz?N)rN   rM   rS   sleepr%   s    r   stopzConnectionManager.stop   s(    
  $mmJJt mmr   c                 \    d| _         	 | j                  |       d| _         y# d| _         w xY w)a  Run the connections selector indefinitely.

        Args:
            expiration_interval (float): Interval, in seconds, at which
                connections will be checked for expiration.

        Connections that are ready to process are submitted via
        self.server.process_conn()

        Connections submitted for processing must be `put()`
        back if they should be examined again for another request.

        Can be shut down by calling `stop()`.
        TFN)rM   _run)r&   expiration_intervals     r   runzConnectionManager.run   s,     	"II)*!DMEDMs   " 	+c                    t        j                          }t        rt        |d      }n|}| j                  s	 | j                  j                  |      }|D ]  \  }}|| j                  u rD| j                  | j                  j                        }|<| j                  j                  |       X| j                  j                  |       | j                  j                  |        t        j                          }||z
  |kD  r+| j                  || j                  j                  z
         |}| j                  syy# t        $ r | j                          Y /w xY w)a  Run connection handler loop until stop was requested.

        :param expiration_interval: Interval, in seconds, at which \
                                    connections will be checked for \
                                    expiration.
        :type expiration_interval: float

        Use ``expiration_interval`` as ``select()`` timeout
        to assure expired connections are closed in time.

        On Windows cap the timeout to 0.05 seconds
        as ``select()`` does not return when a socket is ready.
        g?r?   N)rZ   )rS   r   minrN   r!   rA   OSError_remove_invalid_socketsrO   _from_server_socketrP   rW   r9   r\   r@   )	r&   rb   last_expiration_checkselect_timeoutactive_listr0   r1   new_connnows	            r   ra   zConnectionManager._run   s/    !%		 !!4d;N0N&&"nn33N3K
 $/ 
3$4;;&#778J8JKH+00: NN--g6KK,,T2
3 ))+C++/BBsT[[-@-@'@A(+%- &&  ,,.s   D= =EEc                    g }| j                   j                  D ]*  \  }}|| j                  u r	 t        j                  |       , |D ]H  \  }}| j                   j                  |       t        t
              5  |j                          ddd       J y# t
        $ r |j                  ||f       Y w xY w# 1 sw Y   wxY w)a  Clean up the resources of any broken connections.

        This method attempts to detect any connections in an invalid state,
        unregisters them from the selector and closes the file descriptors of
        the corresponding network sockets where possible.
        N)
r!   r2   rO   osfstatrf   appendr9   r   rC   )r&   invalid_connsr0   r1   s       r   rg   z)ConnectionManager._remove_invalid_sockets   s     !^^77 	6MGTt{{"6!	6 + 	MGTNN%%g. '" 

 	  6$$gt_56 s   B8B6B32B36B?	c                 N   	 |j                         \  }}| j                  j                  d   r!| j                  j                  dxx   dz  cc<   t        |       t	        |d      r%|j                  | j                  j                         t        }i }| j                  j                  z	 | j                  j                  j                  |      \  }}| j                  j                  j0                  }t	        |d      r%|j                  | j                  j                         | j                  j3                  | j                  ||      }t5        | j                  j6                  t8        t:        f      s7|!t        |j=                               dk(  rd}nd}|d   |_        |d   |_         ||_!        |S # t        j                  $ r+}| j                  j                  d|d|       Y d }~y d }~wt        j                  $ r}| j                  j                  d|d|       d}d	| j                  j                  z  d
t        |      z  d|g}	 ||dt         j"                        }
	 |
j%                  dj'                  |	      j)                  d             n6# t*        $ r*}|j,                  d   t        j.                  vr Y d }~nd }~ww xY wY d }~y d }~ww xY w# tD        j                  $ r Y y t*        $ r}| j                  j                  d   r!| j                  j                  dxx   dz  cc<   |j,                  d   t        jF                  v rY d }~y |j,                  d   t        jH                  v rY d }~y |j,                  d   t        j.                  v rY d }~y  d }~ww xY w)NEnabledAcceptsr   
settimeoutzClient uF    lost — peer dropped the TLS connection suddenly, during handshake: u    attempted to speak plain HTTP into a TCP connection configured for TLS-only traffic — trying to send back a plain HTTP error response: zUThe client sent a plain HTTP request, but this server only speaks HTTPS on this port.z%s 400 Bad Request
zContent-Length: %s
zContent-Type: text/plain

wb z
ISO-8859-1r      )z0.0.0.0r   )z::r   zSocket Errors)%acceptrO   statsr   hasattrrv   r@   r   ssl_adapterwrapr   FatalSSLAlert	error_log
NoSSLErrorprotocolr)   ioDEFAULT_BUFFER_SIZEwritejoinencoderf   argssocket_errors_to_ignoremakefileConnectionClass
isinstance	bind_addrstrbytesgetsocknameremote_addrremote_portssl_envrP   socket_error_eintrsocket_errors_nonblocking)r&   server_socketsaddrmfr   tls_connection_drop_errorhttp_over_https_errmsgbufwfileexr1   s                r   rh   z%ConnectionManager._from_server_socket  s-   ^	#**,GAt{{  +!!),1,&q)q,'T[[001BG{{&&2!!%!8!8!=!=a!@JAwB [[,,551l+LL!4!45;;..t{{ArBDdkk33c5\B <1==?+q0-  )#'7 #'7 "DLKm ++ KK))!$ +B48:
 (( KK))!$ +L /24F 
 14;;3G3GG03s8;:	C q$(>(>?E"BGGCL$7$7$EF" "771:V-K-KK! L" 1b ~~ 	  	{{  +!!/2a72wwqzV666 wwqzV=== wwqzV;;; '	s   B'K *(F4 C!K 4K!G-(K -KA$K(/JK	K! KKKKK KK N$0N$8ANN:NNN$c                     | j                   j                  D ]$  \  }}|| j                  us|j                          & | j                   j                          y)z Close all monitored connections.N)r!   r2   rO   rC   )r&   r/   r1   s      r   rC   zConnectionManager.closey  sF    33 	IQ4;;&

	 	r   c                 2    t        | j                        dz
  S )zReturn the current number of connections.

        Includes all connections registered with the selector,
        minus one for the server socket, which is always registered
        with the selector.
        r   )r)   r!   r%   s    r   _num_connectionsz"ConnectionManager._num_connections  s     4>>"Q&&r   c                 X    | j                   j                  }|du xs | j                  |k  S )z>Flag whether it is allowed to add a new keep-alive connection.N)rO   keep_alive_conn_limitr   )r&   ka_limits     r   can_add_keepalive_connectionz.ConnectionManager.can_add_keepalive_connection  s.     ;;444C4#8#88#CCr   N)rD   rE   rF   rG   r'   rX   r\   r_   rc   ra   rg   rh   rC   rH   r   r   r   r   r   rJ   rJ   o   sa    

$ *"*3,j2_B ' ' D Dr   rJ   )!rG   r   ro   rP   r"   rS   r   
contextlibr   rx   r   _compatr   r   r   r
   r   ImportErrorctypesr   r   ctypes.wintypeskernel32SetHandleInformationr   wintypesHANDLEDWORDargtypesBOOLrestyper   rJ   r   r   r   <module>r      s    + 	 	        E2E<# <#~_D _D}  !!+ & D DOO""OO!!OO!!*
&
 )/(<(<%	!  	!s6   A C.BCC.C(%C.'C((C.-C.