o
    bU                     @   s   d 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
 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u rKd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/>}.
    )Sequence)exc_info)warn)implementer)blockingCallFromThread)Logger)Failure)INTERNAL_SERVER_ERROR)	IResource)NOT_DONE_YETc                 C   s   t | tr| 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-1)
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   _wsgiStringToBytes8   s   r   c                 C   s$   t | tr| d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   )r   r   r   decoder   r   r   r   r   D   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   U   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s"ttu 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)wsgiT)systemisErrormessageN)
r   r   bytesr   type__name__UnicodeWarning	TypeError_logerror)selfdatar   r   r   writep   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%   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   b   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__      
z_InputStream.__init__Nc                 C      |du 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)r2   readr%   sizer   r   r   r7         
z_InputStream.readc                 C   s&   |dks|du 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)r2   readliner8   r   r   r   r<      s   	
z_InputStream.readlinec                 C   r6   )z
        Pass through to the underlying C{readlines}.

        This is called in a WSGI application thread, not the I/O thread.
        N)r2   	readlinesr8   r   r   r   r=      r:   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.
        )iterr2   r,   r   r   r   __iter__   r5   z_InputStream.__iter__N)	r    r.   r/   r0   r4   r7   r<   r=   r?   r   r   r   r   r1      s    



r1   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r$dd	|j }nd}|j
r2dd	|j
 }nd}|jdd}t|dkrDd}n|d }t|jt| jt|t|t|t|dpbdt|dpjdt| tt| jt|jd	
| _d | j_|j D ]!\}	}
d
t|	 dd }	d	dd |
D dd| j|	< q| jd| rdpddddt  t!|j"d d S )NF   /       ?   s   content-typer(   s   content-length)
REQUEST_METHODREMOTE_ADDRSCRIPT_NAME	PATH_INFOQUERY_STRINGCONTENT_TYPECONTENT_LENGTHSERVER_NAMESERVER_PORTSERVER_PROTOCOLHTTP_-_,c                 s   s    | ]}t |V  qd S r@   )r   ).0vr   r   r   	<genexpr>9  s    z)_WSGIResponse.__init__.<locals>.<genexpr>
 )rE   r   httpshttpT)zwsgi.versionzwsgi.url_schemezwsgi.run_oncezwsgi.multithreadzwsgi.multiprocesszwsgi.errorsz
wsgi.input)#startedreactor
threadpoolapplicationrequestnotifyFinishaddBoth	_finishedprepathr)   postpathurisplitlenr   methodgetClientAddresshost	getHeadergetRequestHostnamer   getHostportclientprotoenvirondefaultContentTyperequestHeadersgetAllRawHeadersupperreplaceupdateisSecurer   r1   content)r%   r\   r]   r^   r_   
scriptNamepathInfopartsqueryStringnamevaluesr   r   r   r4   	  sV   
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%   ignoredr   r   r   rb   W  s   
z_WSGIResponse._finishedNc                 C   s(  | j r|dur|d |d t|ts td|t|jt|tr&nt|t	r9t
d|t|jf td ntd|t|jf |D ]D}t|trNnt|t	rat
d|t|jf td ntd	|t|jf t|dkrytd
||D ]}t|tstd|q{qF|| _|| _| 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.
        NrE      z!status must be str, not {!r} ({})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 z%header must be (str, str) tuple, not )r[   with_tracebackr   r   r"   formatr   r    listr   r   RuntimeWarningtuplerg   statusheadersr'   )r%   r   r   excInfoheaderelemr   r   r   startResponse^  s^   


	



z_WSGIResponse.startResponsec                    s0    fdd}zt j|jW d_S d_w )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 r@   )_sendResponseHeadersr_   r'   r[   r&   r%   r   r   	wsgiWrite  s   z&_WSGIResponse.write.<locals>.wsgiWriteT)r   r\   r[   )r%   r&   r   r   r   r   r'     s   !z_WSGIResponse.writec                 C   sd   | j dd\}}t|}| j|t| | jD ]\}}| dvr/| jj	t|t| qd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.
        NrE   )serverdate)
r   rf   intr_   setResponseCoder   r   lowerresponseHeadersaddRawHeader)r%   coder   r}   valuer   r   r   r     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)r]   callInThreadrunr,   r   r   r   start  s   z_WSGIResponse.startc                    s   z(   j j}|D ]}|r |  jr nqt|dd}|dur'|  W n tyD    fdd} jj| j	gt
 R   Y nw  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                    sD    j jdt|||d | r j  d S  jt  j  d S )NzWSGI application error)failure)r#   r   r   r_   loseConnectionr   r	   finish)r[   r   r   	tracebackr,   r   r   	wsgiError  s   z$_WSGIResponse.run.<locals>.wsgiErrorc                    s$    j s| s	    j  d S d S r@   )r   r   r_   r   r   r,   r   r   
wsgiFinish  s
   z%_WSGIResponse.run.<locals>.wsgiFinishT)r^   rp   r   r'   r   getattrBaseExceptionr\   callFromThreadr[   r   )r%   appIteratorr   r   r   r   r   r,   r   r     s&   


z_WSGIResponse.runr@   )r    r.   r/   r0   r   r   r#   r4   rb   r   r'   r   r   r   r   r   r   r   rA      s    !N
F+rA   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 r@   )_reactor_threadpool_application)r%   r\   r]   r^   r   r   r   r4   (  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.
        )rA   r   r   r   r   r   )r%   r_   responser   r   r   render-  s
   
zWSGIResource.renderc                 C      t d)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 WSGIResourceRuntimeError)r%   r}   r_   r   r   r   getChildWithDefault=     z WSGIResource.getChildWithDefaultc                 C   r   )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 WSGIResourcer   )r%   pathchildr   r   r   putChildE  r   zWSGIResource.putChildN)	r    r.   r/   r0   isLeafr4   r   r   r   r   r   r   r   r     s    r   N)r0   collections.abcr   sysr   warningsr   zope.interfacer   twisted.internet.threadsr   twisted.loggerr   twisted.python.failurer   twisted.web.httpr	   twisted.web.resourcer
   twisted.web.serverr   r   r   r   r   r   r1   rA   r   __all__r   r   r   r   <module>   s0   
C?  3
8