
    g7                     "   d Z ddlZddlmZ ddlmZ ddlmZmZ  G d dej                        Z
 G d	 d
ej                        Z G d de      Z G d de      Zej                         Z G d d      Z e       j%                  e
eeee       y)a  This class holds Cheroot WSGI server implementation.

Simplest example on how to use this server::

    from cheroot import wsgi

    def my_crazy_app(environ, start_response):
        status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        start_response(status, response_headers)
        return [b'Hello world!']

    addr = '0.0.0.0', 8070
    server = wsgi.Server(addr, my_crazy_app)
    server.start()

The Cheroot WSGI server can serve as many WSGI applications
as you want in one instance by using a PathInfoDispatcher::

    path_map = {
        '/': my_crazy_app,
        '/blog': my_blog_app,
    }
    d = wsgi.PathInfoDispatcher(path_map)
    server = wsgi.Server(addr, d)
    N   )server)
threadpool)ntobbtonc                   h     e Zd ZdZdZ	 	 	 	 	 	 d fd	Zed        Zej                  d        Z xZ	S )Serverz8A subclass of HTTPServer which calls a WSGI application.r   r   c                     t         t        |   |t        | j                     ||||       || _        || _        || _        || _        t        j                  | |xs d||	|
      | _        y)a  Initialize WSGI Server instance.

        Args:
            bind_addr (tuple): network interface to listen to
            wsgi_app (callable): WSGI application callable
            numthreads (int): number of threads for WSGI thread pool
            server_name (str): web server name to be advertised via
                Server HTTP header
            max (int): maximum number of worker threads
            request_queue_size (int): the 'backlog' arg to
                socket.listen(); max queued connections
            timeout (int): the timeout in seconds for accepted connections
            shutdown_timeout (int): the total time, in seconds, to
                wait for worker threads to cleanly exit
            accepted_queue_size (int): maximum number of active
                requests in queue
            accepted_queue_timeout (int): timeout for putting request
                into queue
        )gatewayserver_namepeercreds_enabledpeercreds_resolve_enabled
reuse_portr   )minmaxaccepted_queue_sizeaccepted_queue_timeoutN)superr	   __init__wsgi_gatewayswsgi_versionwsgi_apprequest_queue_sizetimeoutshutdown_timeoutr   
ThreadPoolrequests)self	bind_addrr   
numthreadsr   r   r   r   r   r   r   r   r   r   	__class__s                 !/opt/Tautulli/lib/cheroot/wsgi.pyr   zServer.__init__)   sy    4 	fd$!$"3"34#/&?! 	% 	
 !"4 0"--joA3 3#9
    c                 .    | j                   j                  S )zSet minimum number of threads.r   r   r   s    r#   r!   zServer.numthreadsU   s     }}   r$   c                 &    || j                   _        y Nr&   )r   values     r#   r!   zServer.numthreadsZ   s    !r$   )
   N   r+   r-   r,   r+   FFF)
__name__
__module____qualname____doc__r   r   propertyr!   setter__classcell__r"   s   @r#   r	   r	   #   sT    BL) ?CCD79;@*
X ! ! " "r$   r	   c                   \     e Zd ZdZ fdZed        Zd Zd Zd	dZ	e
d        Zd Z xZS )
Gatewayz/A base class to interface HTTPServer with WSGI.c                 r    t         t        |   |       d| _        | j	                         | _        d| _        y)zzInitialize WSGI Gateway instance with request.

        Args:
            req (HTTPRequest): current HTTP request
        FN)r   r7   r   started_responseget_environenvremaining_bytes_out)r   reqr"   s     r#   r   zGateway.__init__b   s4     	gt%c* %##%#' r$   c                 ^    | j                         D ci c]  }|j                  | c}S c c}w )zCreate a mapping of gateways and their versions.

        Returns:
            dict[tuple[int,int],class]: map of gateway version and
                corresponding class

        )__subclasses__version)clsgws     r#   gateway_mapzGateway.gateway_mapm   s)     *-););)=>2

B>>>s   *c                     t         );Return a new environ dict targeting the given wsgi.version.)NotImplementedErrorr'   s    r#   r:   zGateway.get_environx   s    !!r$   c                    | j                   j                  j                  | j                  | j                        }	 t        d|      D ].  }t        |t              st        d      | j                  |       0 	 | j                   j                          t        |d      r|j                          yy# | j                   j                          t        |d      r|j                          w w xY w)a  Process the current request.

        From :pep:`333`:

            The start_response callable must not actually transmit
            the response headers. Instead, it must store them for the
            server or gateway to transmit only after the first
            iteration of the application return value that yields
            a NON-EMPTY string, or upon the application's first
            invocation of the write() callable.
        Nz"WSGI Applications must yield bytesclose)r=   r   r   r;   start_responsefilter
isinstancebytes
ValueErrorwriteensure_headers_senthasattrrH   )r   responsechunks      r#   respondzGateway.respond|   s     88??++DHHd6I6IJ		!h/ "!%/$%IJJ

5!" HH((*x)  * HH((*x)  *s   =B2 29C+c                    | j                   r|st        d      d| _         | j                  j                  r|d   }|| j	                  |      | j                  _        |D ]  \  }}t        |t              st        d|z        t        |t              st        d|z        |j                         dk(  rt        |      | _        t        |      t        |      f}| j                  j                  j                  |        | j                  S )z)WSGI callable to begin the HTTP response.z:WSGI start_response called a second time with no exc_info.Tr   z/WSGI response header key %r is not of type str.z1WSGI response header value %r is not of type str.zcontent-length)r9   RuntimeErrorr=   sent_headers_encode_statusstatusrK   str	TypeErrorlowerintr<   r   
outheadersappendrN   )r   rX   headersexc_infor*   kv
out_headers           r#   rI   zGateway.start_response   s      )  !%
 88  QKEK--f5 	3DAqa%EI  a%G!K  wwy,,+.q6(a$q')JHH&&z2	3 zzr$   c                 Z    t        | t              st        d      | j                  d      S )a:  Cast status to bytes representation of current Python version.

        According to :pep:`3333`, when using Python 3, the response status
        and headers must be bytes masquerading as Unicode; that is, they
        must be of type "str" but are restricted to code points in the
        "Latin-1" set.
        z(WSGI response status is not of type str.
ISO-8859-1)rK   rY   rZ   encode)rX   s    r#   rW   zGateway._encode_status   s)     &#&FGG}}\**r$   c                 x   | j                   st        d      t        |      }| j                  }|=||kD  r8| j                  j
                  s| j                  j                  dd       n|d| }| j                  j                          | j                  j                  |       |||z  }|dk  rt        d      yy)zWSGI callable to write unbuffered data to the client.

        This method is also used internally by start_response (to write
        data from the iterable returned by the WSGI application).
        z(WSGI write called before start_response.Nz500 Internal Server ErrorzLThe requested resource returned more bytes than the declared Content-Length.r   z2Response body exceeds the declared Content-Length.)
r9   rU   lenr<   r=   rV   simple_responserO   rN   rM   )r   rR   chunklenrbos       r#   rN   zGateway.write   s     $$IJJu:&&?x#~88((((// ds$$&u?8OCQw H   r$   r)   )r.   r/   r0   r1   r   classmethodrC   r:   rS   rI   staticmethodrW   rN   r4   r5   s   @r#   r7   r7   _   sH    9	( ? ?"!0"H 
+ 
+!r$   r7   c                       e Zd ZdZdZd Zy)
Gateway_10z8A Gateway class to interface HTTPServer with WSGI 1.0.x.r
   c                    | j                   }|j                  }i d|j                  j                  dt	        |j
                        dt	        |j                        d|j                  xs ddt        |j                  xs d      dt	        |j                        dt	        |j                        d	dd
|j                  j                  dt	        |j                        d|j                  j                  dt        j                   d|j"                  dt%        |j&                        ddddddt	        |j(                        | j*                  d}t-        |j                  j.                  t              rd|d<   	 t        |j0                        |d<   t        |j2                        |d<   t        |j4                        |d<   t        |j6                        |d<   t        |j8                        |d<   |d   |d<   n%t        |j                  j.                  d         |d<   |j=                  d |j>                  jA                         D               |jC                  dd       }|||d!<   |jC                  d"d       }|||d#<   |j                  jD                  r%|j=                  |j                  jD                         |S # t:        $ r Y w xY w)$rE   ACTUAL_SERVER_PROTOCOL	PATH_INFOQUERY_STRINGREMOTE_ADDR REMOTE_PORTREQUEST_METHODREQUEST_URISCRIPT_NAMESERVER_NAMESERVER_PROTOCOLSERVER_SOFTWAREzwsgi.errorsz
wsgi.inputzwsgi.input_terminatedzwsgi.multiprocessFzwsgi.multithreadTzwsgi.run_once)zwsgi.url_schemezwsgi.versionSERVER_PORTX_REMOTE_PIDX_REMOTE_UIDX_REMOTE_GIDX_REMOTE_USERX_REMOTE_GROUPREMOTE_USERr   c              3      K   | ]K  \  }}d j                  t        |      j                         j                  dd            t        |      f M yw)zHTTP_{header_name!s}-_)header_nameN)formatr   upperreplace).0ra   rb   s      r#   	<genexpr>z)Gateway_10.get_environ.<locals>.<genexpr>#  sM      
 1	 '47==?#:#:3#DEQ
s   AAHTTP_CONTENT_TYPENCONTENT_TYPEHTTP_CONTENT_LENGTHCONTENT_LENGTH)#r=   connr   protocolr   pathqsremote_addrrY   remote_portmethodurir   request_protocolsoftwaresysstderrrfileboolchunked_readschemer@   rK   r    peer_pidpeer_uidpeer_gid	peer_user
peer_grouprU   update	inheadersitemspopssl_env)r   r=   req_connr;   ctcls         r#   r:   zGateway_10.get_environ   s   hh88
 %cjj&9&9	

 chh
 DL
 8//52
 3x339r:
 d3::.
 4=
 2
 3::11
 tC$8$89
 szz22
  3::!
" #))#
$ $T#*:*:%;%
&  '
( )
* U+
,  $CJJ/ LL/
4 cjj**C0 "$C&)(*;*;&<N#&)(*;*;&<N#&)(*;*;&<N#'*8+=+='>O$(+H,?,?(@$%%(%9M" "%SZZ%9%9!%<!=C 	

 
 ++-
 	
 WW($/>"$CWW*D1>$&C !88JJsxx''(
=   s   B K
 
	KKN)r.   r/   r0   r1   r@   r:    r$   r#   ro   ro      s    BGIr$   ro   c                   &     e Zd ZdZdZ fdZ xZS )
Gateway_u0zA Gateway class to interface HTTPServer with WSGI u.0.

    WSGI u.0 is an experimental protocol, which uses Unicode for keys
    and values in both Python 2 and Python 3.
    )ur   c                    | j                   }t        t        |          }t	        |j                               }|j                  dd      }	 |j                  j                  |      |d<   |j                  j                  |      |d<   |j                  |j                                |S # t        $ r d|d<   |d   |d<   |d   |d<   Y Aw xY w)rE   zwsgi.url_encodingzutf-8rr   rs   re   )r=   r   r   r:   dictr   
setdefaultr   decoder   UnicodeDecodeErrorr   )r   r=   env_10r;   encr"   s        r#   r:   zGateway_u0.get_environC  s    hhz4466<<>" nn0':	9"xxs3C"%&&--"4C 	

399;
 " 	9'3C#$%k2C"("8C		9s   <B) )C
	C
)r.   r/   r0   r1   r@   r:   r4   r5   s   @r#   r   r   :  s     G r$   r   c                       e Zd ZdZd Zd Zy)PathInfoDispatcherz6A WSGI dispatcher for dispatch based on the PATH_INFO.c                     	 t        |j                               }d }|j                  |d       |D cg c]  \  }}|j	                  d      |f c}}| _        y# t        $ r Y Mw xY wc c}}w )zInitialize path info WSGI app dispatcher.

        Args:
            apps (dict[str,object]|list[tuple[str,object]]): URI prefix
                and WSGI app pairs
        c                     t        | d         S )Nr   )rh   )apps    r#   by_path_lenz0PathInfoDispatcher.__init__.<locals>.by_path_lenl  s    s1v;r$   T)keyreverse/N)listr   AttributeErrorsortrstripapps)r   r   r   pas        r#   r   zPathInfoDispatcher.__init___  si    	

%D
			k4	0 599DAqahhsmQ'9	  		 :s   A A,	A)(A)c                 ,   |d   xs d}| j                   D ]o  \  }}|j                  dj                  |            s||k(  s-|j                         }|j	                  dd      |z   |d<   |t        |      d |d<    |||      c S   |dd	d
g       dgS )a  Process incoming WSGI request.

        Ref: :pep:`3333`

        Args:
            environ (Mapping): a dict containing WSGI environment variables
            start_response (callable): function, which sets response
                status and headers

        Returns:
            list[bytes]: iterable containing bytes to be returned in
                HTTP response body

        rr   r   z	{path!s}/)r   ry   ru   Nz404 Not Found)zContent-Typez
text/plain)zContent-Length0)r   
startswithr   copygetrh   )r   environrI   r   r   r   s         r#   __call__zPathInfoDispatcher.__call__t  s     {#*sii 	4FAs{11q19:dai!,,.)0]B)G!)K&'+CFG}$7N33	4 	.'	
 tr$   N)r.   r/   r0   r1   r   r   r   r$   r#   r   r   \  s    @:*r$   r   )
WSGIServerWSGIGatewayWSGIGateway_u0WSGIGateway_10WSGIPathInfoDispatcher)r1   r   ru   r   workersr   _compatr   r   
HTTPServerr	   r7   ro   r   rC   r   r   globalsr   r   r$   r#   <module>r      s   6    9"V 9"xGfnn GTN Nb > ##%6 6t 	  -  r$   