U
    W[wU                     @   s   d Z eZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ eekrdd Zdd Zndd Zdd ZG dd dZG dd dZG dd dZeeG dd dZdgZ dS )zo
An implementation of
U{Python Web Server Gateway Interface v1.0.1<http://www.python.org/dev/peps/pep-3333/>}.
    )exc_info)warn)implementer)blockingCallFromThread)reraiseSequence)Failure)	IResource)NOT_DONE_YET)INTERNAL_SERVER_ERROR)Loggerc                 C   s   t | tr| S | dS dS )z
        Convert C{string} to an ISO-8859-1 byte string, if it is not already.

        @type string: C{str}/C{bytes} or C{unicode}
        @rtype: C{str}/C{bytes}

        @raise UnicodeEncodeError: If C{string} contains non-ISO-8859-1 chars.
        
iso-8859-1N)
isinstancestrencodestring r   2/usr/lib/python3/dist-packages/twisted/web/wsgi.py_wsgiString-   s    	
r   c                 C   s   | S )z
        Return C{string} as is; a WSGI string is a byte string in Python 2.

        @type string: C{str}/C{bytes}
        @rtype: C{str}/C{bytes}
        r   r   r   r   r   _wsgiStringToBytes;   s    r   c                 C   s(   t | tr| ddS | dS dS )as  
        Convert C{string} to a WSGI "bytes-as-unicode" string.

        If it's a byte string, decode as ISO-8859-1. If it's a Unicode string,
        round-trip it to bytes and back using ISO-8859-1 as the encoding.

        @type string: C{str} or C{bytes}
        @rtype: C{str}

        @raise UnicodeEncodeError: If C{string} contains non-ISO-8859-1 chars.
        r   N)r   r   r   decoder   r   r   r   r   E   s    
c                 C   s
   |  dS )z
        Convert C{string} from a WSGI "bytes-as-unicode" string to an
        ISO-8859-1 byte string.

        @type string: C{str}
        @rtype: C{bytes}

        @raise UnicodeEncodeError: If C{string} contains non-ISO-8859-1 chars.
        r   )r   r   r   r   r   r   V   s    
c                   @   s.   e Zd ZdZe Zdd Zdd Zdd ZdS )	_ErrorStreama  
    File-like object instances of which are used as the value for the
    C{'wsgi.errors'} key in the C{environ} dictionary passed to the application
    object.

    This simply passes writes on to L{logging<twisted.logger>} system as
    error events from the C{'wsgi'} system.  In the future, it may be desirable
    to expose more information in the events it logs, such as the application
    object which generated the message.
    c                 C   s^   t |tsDttkr.td|t|jf td ntd|t|jf | jj	|dd|fd dS )aG  
        Generate an event for the logging system with the given bytes as the
        message.

        This is called in a WSGI application thread, not the I/O thread.

        @type data: str

        @raise TypeError: On Python 3, if C{data} is not a native string. On
            Python 2 a warning will be issued.
        z+write() argument should be str, not %r (%s)categoryz)write() argument must be str, not %r (%s)ZwsgiT)systemZisErrormessageN)
r   r   bytesr   type__name__UnicodeWarning	TypeError_logerror)selfdatar   r   r   writeq   s&    
 z_ErrorStream.writec                 C   s   |  d| dS )a  
        Join the given lines and pass them to C{write} to be handled in the
        usual way.

        This is called in a WSGI application thread, not the I/O thread.

        @param iovec: A C{list} of C{'\n'}-terminated C{str} which will be
            logged.

        @raise TypeError: On Python 3, if C{iovec} contains any non-native
            strings. On Python 2 a warning will be issued.
         N)r&   join)r$   Ziovecr   r   r   
writelines   s    z_ErrorStream.writelinesc                 C   s   dS )z
        Nothing is buffered, so flushing does nothing.  This method is required
        to exist by PEP 333, though.

        This is called in a WSGI application thread, not the I/O thread.
        Nr   r$   r   r   r   flush   s    z_ErrorStream.flushN)	r   
__module____qualname____doc__r   r"   r&   r)   r+   r   r   r   r   r   d   s
   
r   c                   @   s>   e Zd ZdZdd ZdddZdddZdd	d
Zdd ZdS )_InputStreama  
    File-like object instances of which are used as the value for the
    C{'wsgi.input'} key in the C{environ} dictionary passed to the application
    object.

    This only exists to make the handling of C{readline(-1)} consistent across
    different possible underlying file-like object implementations.  The other
    supported methods pass through directly to the wrapped object.
    c                 C   s
   || _ dS )zt
        Initialize the instance.

        This is called in the I/O thread, not a WSGI application thread.
        N)_wrapped)r$   inputr   r   r   __init__   s    z_InputStream.__init__Nc                 C   s   |dkr| j  S | j |S )z
        Pass through to the underlying C{read}.

        This is called in a WSGI application thread, not the I/O thread.
        N)r0   readr$   sizer   r   r   r3      s    
z_InputStream.readc                 C   s&   |dks|dkr| j  S | j |S )z
        Pass through to the underlying C{readline}, with a size of C{-1} replaced
        with a size of L{None}.

        This is called in a WSGI application thread, not the I/O thread.
        N)r0   readliner4   r   r   r   r7      s    	
z_InputStream.readlinec                 C   s   |dkr| j  S | j |S )z
        Pass through to the underlying C{readlines}.

        This is called in a WSGI application thread, not the I/O thread.
        N)r0   	readlinesr4   r   r   r   r8      s    
z_InputStream.readlinesc                 C   s
   t | jS )z
        Pass through to the underlying C{__iter__}.

        This is called in a WSGI application thread, not the I/O thread.
        )iterr0   r*   r   r   r   __iter__   s    z_InputStream.__iter__)N)N)N)	r   r,   r-   r.   r2   r3   r7   r8   r:   r   r   r   r   r/      s   		


r/   c                   @   sT   e Zd ZdZdZe Zdd Zdd Zddd	Z	d
d Z
dd Zdd Zdd ZdS )_WSGIResponsea$  
    Helper for L{WSGIResource} which drives the WSGI application using a
    threadpool and hooks it up to the L{http.Request}.

    @ivar started: A L{bool} indicating whether or not the response status and
        headers have been written to the request yet.  This may only be read or
        written in the WSGI application thread.

    @ivar reactor: An L{IReactorThreads} provider which is used to call methods
        on the request in the I/O thread.

    @ivar threadpool: A L{ThreadPool} which is used to call the WSGI
        application object in a non-I/O thread.

    @ivar application: The WSGI application object.

    @ivar request: The L{http.Request} upon which the WSGI environment is
        based and to which the application's output will be sent.

    @ivar environ: The WSGI environment L{dict}.

    @ivar status: The HTTP response status L{str} supplied to the WSGI
        I{start_response} callable by the application.

    @ivar headers: A list of HTTP response headers supplied to the WSGI
        I{start_response} callable by the application.

    @ivar _requestFinished: A flag which indicates whether it is possible to
        generate more response data or not.  This is L{False} until
        L{http.Request.notifyFinish} tells us the request is done,
        then L{True}.
    Fc                 C   s  d| _ || _|| _|| _|| _| j | j |jrHdd	|j }nd}|j
rddd	|j
 }nd}|jdd}t|dkrd}n|d }t|jt| jt|t|t|t|dpdt|dpdt| tt| jt|jd	
| _d | j_|j D ]D\}	}
d
t|	 dd }	d	dd |
D dd| j|	< q| jd| rpdprddddt  t!|j"d d S )NF   /       ?   s   content-typer'   s   content-length)
ZREQUEST_METHODZREMOTE_ADDRZSCRIPT_NAMEZ	PATH_INFOZQUERY_STRINGZCONTENT_TYPEZCONTENT_LENGTHZSERVER_NAMEZSERVER_PORTZSERVER_PROTOCOLZHTTP_-_,c                 s   s   | ]}t |V  qd S N)r   ).0vr   r   r   	<genexpr>C  s    z)_WSGIResponse.__init__.<locals>.<genexpr>
 )r?   r   ZhttpsZhttpT)zwsgi.versionzwsgi.url_schemezwsgi.run_oncezwsgi.multithreadzwsgi.multiprocesszwsgi.errorsz
wsgi.input)#startedreactor
threadpoolapplicationrequestZnotifyFinishZaddBoth	_finishedZprepathr(   ZpostpathZurisplitlenr   methodZgetClientAddressZhostZ	getHeaderZgetRequestHostnamer   ZgetHostZportZclientprotoenvironZdefaultContentTypeZrequestHeadersZgetAllRawHeadersupperreplaceupdateZisSecurer   r/   Zcontent)r$   rJ   rK   rL   rM   Z
scriptNameZpathInfopartsZqueryStringnamevaluesr   r   r   r2     sb    

 z_WSGIResponse.__init__c                 C   s
   d| _ dS )zc
        Record the end of the response generation for the request being
        serviced.
        TN)_requestFinished)r$   Zignoredr   r   r   rN   ^  s    z_WSGIResponse._finishedNc                 C   s(  | j r |dk	r t|d |d  t|ts@td|t|jf t|trLn<t|trrt	d|t|jf t
d ntd|t|jf |D ]}t|trn<t|trt	d|t|jf t
d ntd	|t|jf t|dkrtd
|f |D ]}t|tstd|f qq|| _|| _| jS )z
        The WSGI I{start_response} callable.  The given values are saved until
        they are needed to generate the response.

        This will be called in a non-I/O thread.
        Nr?      zstatus must be str, not %r (%s)z%headers should be a list, not %r (%s)r   z#headers must be a list, not %r (%s)z0header should be a (str, str) tuple, not %r (%s)z.header must be a (str, str) tuple, not %r (%s)z)header must be a (str, str) tuple, not %rz'header must be (str, str) tuple, not %r)rI   r   r   r   r!   r   r   listr   r   RuntimeWarningtuplerP   statusheadersr&   )r$   r^   r_   ZexcInfoheaderelemr   r   r   startResponsef  sj    


 

 
z_WSGIResponse.startResponsec                    s0    fdd}ztj|j W S d_ X dS )a   
        The WSGI I{write} callable returned by the I{start_response} callable.
        The given bytes will be written to the response body, possibly flushing
        the status and headers first.

        This will be called in a non-I/O thread.
        c                    s   | s   j  d S rC   )_sendResponseHeadersrM   r&   rI   r%   r$   r   r   	wsgiWrite  s    z&_WSGIResponse.write.<locals>.wsgiWriteTN)rI   r   rJ   )r$   r%   rf   r   re   r   r&     s    !  z_WSGIResponse.writec                 C   sd   | j dd\}}t|}| j|t| | jD ],\}}| dkr2| jj	t|t| q2dS )a,  
        Set the response code and response headers on the request object, but
        do not flush them.  The caller is responsible for doing a write in
        order for anything to actually be written out in response to the
        request.

        This must be called in the I/O thread.
        Nr?   )Zserverdate)
r^   rO   intrM   setResponseCoder   r_   lowerZresponseHeadersZaddRawHeader)r$   coder   rW   valuer   r   r   rc     s    	 z"_WSGIResponse._sendResponseHeadersc                 C   s   | j | j dS )zo
        Start the WSGI application in the threadpool.

        This must be called in the I/O thread.
        N)rK   ZcallInThreadrunr*   r   r   r   start  s    z_WSGIResponse.startc                    s   zP   j j}|D ]}|r( |  jr q4qt|dd}|dk	rN|  W n0    fdd} jj| jft	   Y nX  fdd} j| j d _dS )z
        Call the WSGI application object, iterate it, and handle its output.

        This must be called in a non-I/O thread (ie, a WSGI application
        thread).
        closeNc                    sB    j jdt|||d | r( j  n jt  j  d S )NzWSGI application error)failure)r"   rp   r   rM   ZloseConnectionri   r   finish)rI   r   rl   	tracebackr*   r   r   	wsgiError  s    
z$_WSGIResponse.run.<locals>.wsgiErrorc                    s     j s| s    j  d S rC   )rY   rc   rM   rq   rd   r*   r   r   
wsgiFinish  s    z%_WSGIResponse.run.<locals>.wsgiFinishT)
rL   rR   rb   r&   rY   getattrrJ   ZcallFromThreadrI   r   )r$   ZappIteratorra   ro   rs   rt   r   r*   r   rm     s     


z_WSGIResponse.run)N)r   r,   r-   r.   rY   r   r"   r2   rN   rb   r&   rc   rn   rm   r   r   r   r   r;      s   !L
A-	r;   c                   @   s4   e Zd ZdZdZdd Zdd Zdd Zd	d
 ZdS )WSGIResourcea  
    An L{IResource} implementation which delegates responsibility for all
    resources hierarchically inferior to it to a WSGI application.

    @ivar _reactor: An L{IReactorThreads} provider which will be passed on to
        L{_WSGIResponse} to schedule calls in the I/O thread.

    @ivar _threadpool: A L{ThreadPool} which will be passed on to
        L{_WSGIResponse} to run the WSGI application object.

    @ivar _application: The WSGI application object.
    Tc                 C   s   || _ || _|| _d S rC   )_reactor_threadpool_application)r$   rJ   rK   rL   r   r   r   r2   ,  s    zWSGIResource.__init__c                 C   s    t | j| j| j|}|  tS )a  
        Turn the request into the appropriate C{environ} C{dict} suitable to be
        passed to the WSGI application object and then pass it on.

        The WSGI application object is given almost complete control of the
        rendering process.  C{NOT_DONE_YET} will always be returned in order
        and response completion will be dictated by the application object, as
        will the status, headers, and the response body.
        )r;   rw   rx   ry   rn   r
   )r$   rM   Zresponser   r   r   render2  s    
   zWSGIResource.renderc                 C   s   t ddS )z
        Reject attempts to retrieve a child resource.  All path segments beyond
        the one which refers to this resource are handled by the WSGI
        application object.
        z/Cannot get IResource children from WSGIResourceNRuntimeError)r$   rW   rM   r   r   r   getChildWithDefaultB  s    z WSGIResource.getChildWithDefaultc                 C   s   t ddS )z
        Reject attempts to add a child resource to this resource.  The WSGI
        application object handles all path segments beneath this resource, so
        L{IResource} children can never be found.
        z0Cannot put IResource children under WSGIResourceNr{   )r$   pathZchildr   r   r   putChildK  s    zWSGIResource.putChildN)	r   r,   r-   r.   ZisLeafr2   rz   r}   r   r   r   r   r   rv     s   	rv   N)!r.   r   Z__metaclass__sysr   warningsr   Zzope.interfacer   Ztwisted.internet.threadsr   Ztwisted.python.compatr   r   Ztwisted.python.failurer   Ztwisted.web.resourcer	   Ztwisted.web.serverr
   Ztwisted.web.httpr   Ztwisted.loggerr   r   r   r   r   r   r/   r;   rv   __all__r   r   r   r   <module>   s0   

FC  .: