
    g6@                         d 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 Z G d d	e      Z G d
 de      Z G d de      Z G d de      Z G d de      Z G d de      Zy)a  WSGI interface (see PEP 333 and 3333).

Note that WSGI environ keys and values are 'native strings'; that is,
whatever the type of "" is. For Python 2, that's a byte string; for
Python 3, it's a unicode string. But PEP 3333 says: "even if Python's
str type is actually Unicode "under the hood", the content of native
strings must still be translatable to bytes via the Latin-1 encoding!"
    N)ntou)_cperror)httputil)is_closable_iteratorc                 D   i }| t        d         }| j                         j                         D ]n  \  }}|t        d      t        d      t        d      fv r|j                  |      }n!t	        |t
              r|j                  d      }|||j                  d      <   p |S )zLReturn a new environ dict for WSGI 1.x from the given WSGI u.x environ.
    wsgi.url_encoding	PATH_INFOSCRIPT_NAMEQUERY_STRING
ISO-8859-1)r   copyitemsencode
isinstancestr)environenv1xurl_encodingkvs        %/opt/Tautulli/lib/cherrypy/_cpwsgi.pydowngrade_wsgi_ux_to_1xr      s     E4 345L$$& *1k"D$7n9MNN&A3&A()ahh|$%* L    c                   0    e Zd ZdZdZ	 dZ	 i Z	 ddZd Zy)VirtualHosta  Select a different WSGI application based on the Host header.

    This can be useful when running multiple sites within one CP server.
    It allows several domains to point to different applications. For example::

        root = Root()
        RootApp = cherrypy.Application(root)
        Domain2App = cherrypy.Application(root)
        SecureApp = cherrypy.Application(Secure())

        vhost = cherrypy._cpwsgi.VirtualHost(
            RootApp,
            domains={
                'www.domain2.example': Domain2App,
                'www.domain2.example:443': SecureApp,
            },
        )

        cherrypy.tree.graft(vhost)
    NTc                 6    || _         |xs i | _        || _        y N)defaultdomainsuse_x_forwarded_host)selfr   r   r    s       r   __init__zVirtualHost.__init__N   s    }"$8!r   c                     |j                  dd      }| j                  r|j                  d|      }| j                  j                  |      }|| j                  } |||      S )N	HTTP_HOST HTTP_X_FORWARDED_HOST)getr    r   r   )r!   r   start_responsedomainnextapps        r   __call__zVirtualHost.__call__S   s[    ["-$$[[!8&AF,,""6*?llGw//r   NT)	__name__
__module____qualname____doc__r   r    r   r"   r+    r   r   r   r   $   s7    ( G
  I G9
0r   r   c                       e Zd ZdZddZd Zy)InternalRedirectorz>WSGI middleware that handles raised cherrypy.InternalRedirect.c                      || _         || _        y r   )r*   	recursive)r!   r*   r5   s      r   r"   zInternalRedirector.__init__a   s    "r   c                    g }	 |j                         }	 | j                  ||      S # t        j                  $ r% t	        j
                         d   }|j                  dd      }|j                  dd      }|j                  dd      }||z   }|r|d|z   z  }|j                  |       | j                  s[||j                  z   }	|j                  r|	d|j                  z   z  }	|	|v r*|j                  j                          d}
t        |
|	z        d|d	<   |j                  |d<   |j                  |d<   t        j                         |d
<   d|d<   |j                  |d<   Y nw xY wa)N   r
   r%   r	   r   ?z1InternalRedirector visited the same URL twice: %rGETREQUEST_METHOD
wsgi.input0CONTENT_LENGTHcherrypy.previous_request)r   r*   	_cherrypyInternalRedirect_sysexc_infor'   appendr5   pathquery_stringrequestcloseRuntimeErrorioBytesIO)r!   r   r(   redirectionsirsnrD   qsold_urinew_uritmpls              r   r+   zInternalRedirector.__call__e   sf   llnG!B||G^<<-- B]]_Q'[[3{{;3[[4 t)sRx'G##G,~~ !277lG3#88,.

((*O  +4'>:: -2()')ww$*,//'(*

%,/()79zz34?B	 s   ' D6E E N)F)r-   r.   r/   r0   r"   r+   r1   r   r   r3   r3   ^   s    H#%Br   r3   c                   $    e Zd ZdZeeffdZd Zy)ExceptionTrapperz&WSGI middleware that traps exceptions.c                      || _         || _        y r   )r*   throws)r!   r*   rU   s      r   r"   zExceptionTrapper.__init__   s    r   c                 F    t        | j                  ||| j                        S r   )_TrappedResponser*   rU   r!   r   r(   s      r   r+   zExceptionTrapper.__call__   s#    LLKK	
 	
r   N)r-   r.   r/   r0   KeyboardInterrupt
SystemExitr"   r+   r1   r   r   rS   rS      s    0(9:'F 
r   rS   c                   :    e Zd Z eg       Zd Zd Zd Zd Zd Z	y)rW   c                     || _         || _        || _        || _        d| _        | j                  | j                   | j                  | j                        | _        t        | j                        | _        y )NF)	r*   r   r(   rU   started_responsetrapresponseiteriter_response)r!   r*   r   r(   rU   s        r   r"   z_TrappedResponse.__init__   s_    , %		LL$,,(;(;
 "$--0r   c                     d| _         | S r,   )r]   r!   s    r   __iter__z_TrappedResponse.__iter__   s     $r   c                 B    | j                  t        | j                        S r   )r^   nextra   rc   s    r   __next__z_TrappedResponse.__next__   s    yyt1122r   c                 f    t        | j                  d      r| j                  j                          y y )NrG   )hasattrr_   rG   rc   s    r   rG   z_TrappedResponse.close   s%    4=='*MM! +r   c           	         	  ||i |S # | j                   $ r  t        $ r  t        $ rJ t        j                         }t        j                  |d       t
        j                  j                  sd}t        j                  |      \  }}}	 |j                  d      }|D 	cg c]'  \  }}	|j                  d      |	j                  d      f) nc c}	}w }}}	| j                  rt        g       | _        nt        |      | _        	 | j                  ||t        j                                 n%# t        $ r t        j                  dd        w xY w| j                  rdj#                  |      cY S |cY S w xY w)N(   )severityr%   Tr   	tracebackrl   r   )rU   StopIteration	Exceptionr   
format_excr?   logrF   show_tracebacks
bare_errordecoder]   r`   ra   r(   rA   rB   join)
r!   funcargskwargstbshbr   r   s
             r   r^   z_TrappedResponse.trap   sW   '	((({{ 	 	 !	$$&BMM"r*$$44))"-GAq!HH\* !"1 XXl+QXXl-CD   $$%)"X"%)!W"	##Aq$--/:  r: $$xx{"C!	s:   
 BE6#,C7E6%D-,E6-"E E61E65E6N)
r-   r.   r/   r`   r_   r"   rd   rg   rG   r^   r1   r   r   rW   rW      s$    BxH	13"(r   rW   c                   J    e Zd ZdZd Zd Zd Zd Zd Zddd	d
ddZ	d Z
d Zy)AppResponsez1WSGI response iterable for CherryPy applications.c                    || _         	 || _        | j                          t        j                  j
                  }|j                  }t        |t              st        d      g }|j                  D ]X  \  }}t        |t              sd}	t        |	|z        t        |t              sd}	t        |	|z        |j                  ||f       Z 	 |j                  d      }|D cg c]'  \  }}|j                  d      |j                  d      f) }}}t        |j                        | _         |||      | _        y c c}}w # t"        $ r | j%                           w xY w)Nz,response.output_status is not a byte string.z1response.header_list key %r is not a byte string.z3response.header_list value %r is not a byte string.r   )cpappr   runr?   servingr_   output_statusr   bytes	TypeErrorheader_listrC   ru   r`   bodyra   writeBaseExceptionrG   )
r!   r   r(   r   r	outstatus
outheadersr   r   rQ   s
             r   r"   zAppResponse.__init__   sP   
%	"DLHHJ!!**AIi/ NOOJ 	*1!!U+ND#D1H--!!U+M  $D1H--!!1a&)	* 
 &,,\:	 !+1 XXl+QXXl-CD
 
 "&affD'	:>DJ  	JJL	s   CD? !,D9+D? 9D? ?Ec                     | S r   r1   rc   s    r   rd   zAppResponse.__iter__  s    r   c                 ,    t        | j                        S r   )rf   ra   rc   s    r   rg   zAppResponse.__next__  s    D&&''r   c                 :   t         j                  j                  j                  }| j                  j                          |r5t        | j                        r| j                  j                  }	  |        yyy# t        $ r t        j                  dd       Y yw xY w)zQClose and de-reference the current request and response.

        (Core)
        Trk   rm   N)r?   r   r_   streamr   release_servingr   ra   rG   rp   rr   )r!   	streaming
iter_closes      r   rG   zAppResponse.close  s    
 %%..55	

""$ -d.@.@A++11J; B9  ;r:;s   -A7 7 BBc           	         | j                   j                  }t        j                  dt	         |dd      xs d       |dd            }t        j                   |dd      t	         |dd      xs d       |dd            } |d	      } |d
d      }| j
                  j                  ||||      \  }} |d      xs  |d      xs d|_        | j                   d   |_        | j                   d   |_	        | j                   |_
         |dd      |_        | j                   d   }t        j                  | j                   j                  dd      | j                   j                  dd            }	| j                   j                  dd      }
| j                  |	|
      xs |	|
f\  }	}
| j                   j                  d      }| j                  | j                         }| j                   d   }|j                  ||	|
|||       y)z&Create a Request object using environ.r%   SERVER_PORTP   SERVER_NAMEREMOTE_ADDRREMOTE_PORTREMOTE_HOSTzwsgi.url_schemeACTUAL_SERVER_PROTOCOLzHTTP/1.1
LOGON_USERREMOTE_USERNzwsgi.multithreadzwsgi.multiprocessr>   r:   r
   r	   r   SERVER_PROTOCOLr;   )r   r'   r   Hostintr   get_servingloginmultithreadmultiprocesswsgi_environprevurljoinrecode_path_qstranslate_headersr   )r!   envlocalremoteschemesprotorF   respmethrD   rN   rprotoheadersrfiles                 r   r   zAppResponse.run*  s   llM2&,"-r"

 r"M2&,"-r"

 &'-z:

..ufffM
 L)GS-?G4"ll+=>#||,?@#||6=||,-LL]B/LL["-
 \\nb1&&tR0>T2Jb!!"34((6\*D$FGU;r   AuthorizationzContent-LengthzContent-TypezRemote-HostzRemote-Addr)HTTP_CGI_AUTHORIZATIONr=   CONTENT_TYPEr   r   c                    | j                   j                  dd      }| j                  j                  | j                   j                  dd      dd      }|j	                         |j	                         k(  ry 	 |j                  |      j                  |      |j                  |      j                  |      fS # t        t        f$ r Y y w xY w)Nr   r   r	   r%   zrequest.uri_encodingzutf-8)	r   r'   r   find_configlowerr   ru   UnicodeEncodeErrorUnicodeDecodeError)r!   rD   rN   old_encnew_encs        r   r   zAppResponse.recode_path_qs\  s     ,,""#6E**((LL["-"G
 ==?gmmo-	G$++G4		'"))'2  #$67 		s   7?B7 7C	C	c              #      K   |D ]N  }|| j                   v r| j                   |   ||   f (|dd dk(  s1|dd j                  dd      }|||   f P yw)z8Translate CGI-environ header names to HTTP header names.N   HTTP__-)headerNamesreplace)r!   r   cgiNametranslatedHeaders       r   r   zAppResponse.translate_headersu  su      	9G$***&&w/1AAA!'#*12;#6#6sC#@ &(888	9s
   3A!AN)r-   r.   r/   r0   r"   rd   rg   rG   r   r   r   r   r1   r   r   r   r      sB    ;'R(;&(<V #2*&$$K2	9r   r   c                   N    e Zd ZdZdefdefgZ	 dZ	 i Z	 e	Z
	 d	dZd Zd Zd Zy)
	CPWSGIAppz5A WSGI application object for a CherryPy Application.rS   r3   Nc                     || _         | j                  d d  | _        |r| j                  j                  |       | j                  j	                         | _        y r   )r   pipelineextendconfigr   )r!   r   r   s      r   r"   zCPWSGIApp.__init__  sB    
a(MM  *kk&&(r   c                 <    | j                  ||| j                        S )zWSGI application callable for the actual CherryPy application.

        You probably shouldn't call this; call self.__call__ instead, so
        that any WSGI middleware in self.pipeline can run first.
        )response_classr   rX   s      r   tailzCPWSGIApp.tail  s     ""7NDJJGGr   c                     | j                   }|R| j                  }| j                  d d d   D ]*  \  }}| j                  j	                  |i       } ||fi |}, || _          |||      S )Nr   )headr   r   r   r'   )r!   r   r(   r   namecallableconfs          r   r+   zCPWSGIApp.__call__  st    yy< 99D"&--""5 .h{{tR0--. DIG^,,r   c                     |dk(  r| j                   j                  |       y|dk(  r|| _        y|j                  dd      \  }}| j                  j                  |i       }|||<   y)z(Config handler for the 'wsgi' namespace.r   r   .r7   N)r   r   r   splitr   
setdefault)r!   r   r   r   argbuckets         r   namespace_handlerzCPWSGIApp.namespace_handler  s`    
? MM  #"""#DQID#[[++D"5FF3Kr   r   )r-   r.   r/   r0   rS   r3   r   r   r   r   r   r"   r   r+   r   r1   r   r   r   r     s_    ? 
-.	12H DJ F !N)H
-r   r   )r0   sysrA   rI   cherrypyr?   cherrypy._cpcompatr   r   cherrypy.libr   r   r   objectr   r3   rS   rW   r   r   r1   r   r   <module>r      sz     	  #  ! - 70& 70t,B ,B^
v 
 Bv BPY9& Y9xJ Jr   