U
    %_2                     @   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 zdd
lmZ W n  ek
r   dd
lmZ Y nX G dd deZG dd deZdddZG dd deZG dd deZG dd deZeG dd deZG dd deZdS )a  
WSGI Protocol Linter
====================

This module provides a middleware that performs sanity checks on the
behavior of the WSGI server and application. It checks that the
:pep:`3333` WSGI spec is properly implemented. It also warns on some
common HTTP errors such as non-empty responses for 304 status codes.

.. autoclass:: LintMiddleware

:copyright: 2007 Pallets
:license: BSD-3-Clause
    )warn   )implements_iterator)PY2)string_types)Headers)is_entity_header)FileWrapper)urlparsec                   @   s   e Zd ZdZdS )WSGIWarningz Warning class for WSGI warnings.N__name__
__module____qualname____doc__ r   r   K/home/toby/toby_env/lib/python3.8/site-packages/werkzeug/middleware/lint.pyr      s   r   c                   @   s   e Zd ZdZdS )HTTPWarningz Warning class for HTTP warnings.Nr   r   r   r   r   r   "   s   r      c                 C   s(   t |tk	r$td| t |jf t d S )Nz'%s' requires strings, got '%s')typestrr   r   r   )contextobj
stacklevelr   r   r   check_string&   s
    r   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )InputStreamc                 C   s
   || _ d S N_streamselfstreamr   r   r   __init__/   s    zInputStream.__init__c                 G   sB   t |dkrtdtdd nt |dkr6tdtdd | jj| S )Nr   zWSGI does not guarantee an EOF marker on the input stream, thus making calls to 'wsgi.input.read()' unsafe. Conforming servers may never return from this call.r   r      z2Too many parameters passed to 'wsgi.input.read()'.)lenr   r   r   readr    argsr   r   r   r&   2   s    zInputStream.readc                 G   sL   t |dkrtdtdd n$t |dkr8tdtdd ntd| jj| S )Nr   z_Calls to 'wsgi.input.readline()' without arguments are unsafe. Use 'wsgi.input.read()' instead.r   r#   r$   z~'wsgi.input.readline()' was called with a size hint. WSGI does not support this, although it's available on all major servers.z5Too many arguments passed to 'wsgi.input.readline()'.)r%   r   r   	TypeErrorr   readliner'   r   r   r   r*   C   s    zInputStream.readlinec                 C   s<   zt | jW S  tk
r6   tdtdd t d Y S X d S )Nz'wsgi.input' is not iterable.r   r#   r   )iterr   r)   r   r   r    r   r   r   __iter__V   s
    zInputStream.__iter__c                 C   s   t dtdd | j  d S )Nz(The application closed the input stream!r   r#   r   r   r   closer,   r   r   r   r/   ]   s    zInputStream.closeN)r   r   r   r"   r&   r*   r-   r/   r   r   r   r   r   .   s
   r   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )ErrorStreamc                 C   s
   || _ d S r   r   r   r   r   r   r"   c   s    zErrorStream.__init__c                 C   s   t d| | j| d S )Nzwsgi.error.write())r   r   writer    sr   r   r   r1   f   s    
zErrorStream.writec                 C   s   | j   d S r   )r   flushr,   r   r   r   r4   j   s    zErrorStream.flushc                 C   s   |D ]}|  | qd S r   )r1   )r    seqliner   r   r   
writelinesm   s    zErrorStream.writelinesc                 C   s   t dtdd | j  d S )Nz(The application closed the error stream!r   r#   r.   r,   r   r   r   r/   q   s    zErrorStream.closeN)r   r   r   r"   r1   r4   r7   r/   r   r   r   r   r0   b   s
   r0   c                   @   s   e Zd Zdd Zdd ZdS )GuardedWritec                 C   s   || _ || _d S r   )_write_chunks)r    r1   chunksr   r   r   r"   w   s    zGuardedWrite.__init__c                 C   s*   t d| | j| | jt| d S )Nzwrite())r   r9   r1   r:   appendr%   r2   r   r   r   __call__{   s    
zGuardedWrite.__call__N)r   r   r   r"   r=   r   r   r   r   r8   v   s   r8   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )GuardedIteratorc                 C   s:   || _ trt|j| _nt|j| _d| _|| _|| _d S )NF)		_iteratorr   r+   next_next__next__closedheaders_setr;   )r    iteratorrD   r;   r   r   r   r"      s    zGuardedIterator.__init__c                 C   s   | S r   r   r,   r   r   r   r-      s    zGuardedIterator.__iter__c                 C   sN   | j rtdtdd |  }| js0tdtdd td| | jt| |S )Nz Iterated over closed 'app_iter'.r   r#   z8The application returned before it started the response.zapplication iterator items)	rC   r   r   rA   rD   r   r;   r<   r%   )r    rvr   r   r   rB      s    
zGuardedIterator.__next__c                 C   s   d| _ t| jdr| j  | jr| j\}}t| j}|jdtd}|dkr|D ].\}}|	 }|dkrPt
|rPtd| t qP|rtdt nbd	|  krd
k sn |dkr|dkrtd| t |rtd| t n|d k	r||krtdt d S )NTr/   zcontent-length)r   i0  )expireszcontent-locationz'Entity header %r found in 304 response.z#304 responses must not have a body.d         r   z/%r responses must have an empty content length.z"%r responses must not have a body.zGContent-Length and the number of bytes sent to the client do not match.)rC   hasattrr?   r/   rD   sumr;   getintlowerr   r   r   r   )r    status_codeheadersZ
bytes_sentcontent_lengthkey_valuer   r   r   r/      sF    



  zGuardedIterator.closec                 C   s.   | j s*ztdt W n tk
r(   Y nX d S )Nz4Iterator was garbage collected before it was closed.)rC   r   r   	Exceptionr,   r   r   r   __del__   s     zGuardedIterator.__del__N)r   r   r   r"   r-   rB   r/   rV   r   r   r   r   r>      s
   
'r>   c                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )LintMiddlewarea  Warns about common errors in the WSGI and HTTP behavior of the
    server and wrapped application. Some of the issues it check are:

    -   invalid status codes
    -   non-bytestrings sent to the WSGI server
    -   strings returned from the WSGI application
    -   non-empty conditional responses
    -   unquoted etags
    -   relative URLs in the Location header
    -   unsafe calls to wsgi.input
    -   unclosed iterators

    Error information is emitted using the :mod:`warnings` module.

    :param app: The WSGI application to wrap.

    .. code-block:: python

        from werkzeug.middleware.lint import LintMiddleware
        app = LintMiddleware(app)
    c                 C   s
   || _ d S r   )app)r    rX   r   r   r   r"      s    zLintMiddleware.__init__c                 C   s   t |tk	rtdtdd dD ]}||krtd| tdd q|d dkrXtd	tdd |d
d}|dd}|r|d dkrtd| tdd |r|d dkrtd| tdd d S )Nz/WSGI environment is not a standard Python dict.   r#   )	REQUEST_METHODZSERVER_NAMEZSERVER_PORTwsgi.version
wsgi.inputwsgi.errorszwsgi.multithreadzwsgi.multiprocesszwsgi.run_oncez%Required environment key %r not foundr   r[   )r$   r   z"Environ is not a WSGI 1.0 environ.ZSCRIPT_NAME Z	PATH_INFOr   /z-'SCRIPT_NAME' does not start with a slash: %rz+'PATH_INFO' does not start with a slash: %r)r   dictr   r   rM   )r    environrS   script_nameZ	path_infor   r   r   check_environ   s:    zLintMiddleware.check_environc                 C   sb  t d| |d dd }t|dks.| s>ttddd t|dk sV|d dkrfttd	dd t|}|d
k rttddd t|tk	rttddd |D ]z}t|t	k	st|dkrttddd |\}}t|t
k	st|t
k	rttddd | dkrttddd q|d k	rHt|t	sHttddd t|}| | ||fS )Nstatusr$   r   r   z Status code must be three digitsr#   rY    zeInvalid value for status %r.  Valid status strings are three digits, a space and a status explanationrH   zstatus code < 100 detectedzheader list is not a listr   z Headers must tuple 2-item tupleszheader items must be stringszFThe status header is not supported due to conflicts with the CGI spec.zinvalid value for exc_info)r   splitr%   isdigitr   r   rN   r   listtupler   rO   
isinstancer   check_headers)r    rd   rQ   exc_inforP   itemnamevaluer   r   r   check_start_response  sD    
	
z#LintMiddleware.check_start_responsec                 C   s   | d}|d k	rx|drB|dr6ttddd |dd  }|d d |d	d    krfd
ksxn ttddd | d}|d k	rt|jsttddd d S )Netag)zW/w/rr   z%weak etag indicator should be upcase.rY   r#   r   r$   "zunquoted etag emitted.locationz*absolute URLs required for location header)rM   
startswithr   r   r
   netloc)r    rQ   rq   ru   r   r   r   rk   H  s$    


&

zLintMiddleware.check_headersc                 C   s   t |trtdtdd d S )NzThe application returned astring. The response will send one character at a time to the client, which will kill performance. Return a list or iterable instead.r   r#   )rj   r   r   r   )r    app_iterr   r   r   check_iteratora  s    
zLintMiddleware.check_iteratorc                    s   t |dkrtdtdd |r,tdtdd |\}| t|d |d< t|d |d< t|d< g g   fdd	}||}| t	| S )
Nr   zA WSGI app takes two arguments.r#   z+A WSGI app does not take keyword arguments.r\   r]   zwsgi.file_wrapperc                     s   t | dkr"tdt |  tdd |r0tdt | d d \}}t | dkrV| d }nd }|||d d < t||| S )N)r   r   z1Invalid number of arguments: %s, expected 2 or 3.r   r#   z1'start_response' does not take keyword arguments.r   )r%   r   r   rp   r8   )r(   kwargsrd   rQ   rl   r;   rD   r    Zstart_responser   r   checking_start_response  s    


z8LintMiddleware.__call__.<locals>.checking_start_response)
r%   r   r   rc   r   r0   r	   rX   ry   r>   )r    r(   rz   ra   r|   rx   r   r{   r   r=   k  s&      

zLintMiddleware.__call__N)
r   r   r   r   r"   rc   rp   rk   ry   r=   r   r   r   r   rW      s   ,0
rW   N)r   )r   warningsr   _compatr   r   r   Zdatastructuresr   httpr   Zwsgir	   urllib.parser
   ImportErrorWarningr   r   r   objectr   r0   r8   r>   rW   r   r   r   r   <module>   s(   
4P