B
    hAZ1                 @   s   d Z yddlmZ W n  ek
r4   ddlmZ Y nX 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 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G dd deZG dd deZdS )a  
    werkzeug.contrib.lint
    ~~~~~~~~~~~~~~~~~~~~~

    .. versionadded:: 0.5

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

    This module provides a middleware, the :class:`LintMiddleware`.  Wrap your
    application with it and it will warn about common problems with WSGI and
    HTTP while your application is running.

    It's strongly recommended to use it during development.

    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
    :license: BSD, see LICENSE for more details.
    )urlparse)warn)Headers)is_entity_header)FileWrapper)string_typesc               @   s   e Zd ZdZdS )WSGIWarningz Warning class for WSGI warnings.N)__name__
__module____qualname____doc__ r   r   4lib/python3.7/site-packages/werkzeug/contrib/lint.pyr   #   s   r   c               @   s   e Zd ZdZdS )HTTPWarningz Warning class for HTTP warnings.N)r	   r
   r   r   r   r   r   r   r   (   s   r      c             C   s(   t |tk	r$ttd| |jjf  d S )Nz%s requires bytestrings, got %s)typestrr   r   	__class__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__5   s    zInputStream.__init__c             G   sF   t |dkrttddd nt |dkr:ttd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      z/too many parameters passed to wsgi.input.read())lenr   r   r   read)r   argsr   r   r   r    8   s    
zInputStream.readc             G   sP   t |dkrttddd n&t |dkr<ttd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.z2too many arguments passed to wsgi.input.readline())r   r   r   	TypeErrorr   readline)r   r!   r   r   r   r#   D   s    

zInputStream.readlinec             C   s8   y
t | jS  tk
r2   ttddd t dS X d S )Nzwsgi.input is not iterable.r   )r   r   )iterr   r"   r   r   )r   r   r   r   __iter__R   s
    
zInputStream.__iter__c             C   s   t tddd | j  d S )Nz$application closed the input stream!r   )r   )r   r   r   close)r   r   r   r   r&   Y   s    zInputStream.closeN)r	   r
   r   r   r    r#   r%   r&   r   r   r   r   r   3   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 )N)r   )r   r   r   r   r   r   a   s    zErrorStream.__init__c             C   s   t d| | j| d S )Nzwsgi.error.write())r   r   write)r   sr   r   r   r(   d   s    
zErrorStream.writec             C   s   | j   d S )N)r   flush)r   r   r   r   r*   h   s    zErrorStream.flushc             C   s   x|D ]}|  | qW d S )N)r(   )r   seqliner   r   r   
writelinesk   s    
zErrorStream.writelinesc             C   s   t tddd | j  d S )Nz$application closed the error stream!r   )r   )r   r   r   r&   )r   r   r   r   r&   o   s    zErrorStream.closeN)r	   r
   r   r   r(   r*   r-   r&   r   r   r   r   r'   _   s
   r'   c               @   s   e Zd Zdd Zdd ZdS )GuardedWritec             C   s   || _ || _d S )N)_write_chunks)r   r(   chunksr   r   r   r   w   s    zGuardedWrite.__init__c             C   s*   t d| | j| | jt| d S )Nzwrite())r   r/   r(   r0   appendr   )r   r)   r   r   r   __call__{   s    
zGuardedWrite.__call__N)r	   r
   r   r   r3   r   r   r   r   r.   u   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 )GuardedIteratorc             C   s(   || _ t|j| _d| _|| _|| _d S )NF)	_iteratorr$   next_nextclosedheaders_setr1   )r   iteratorr9   r1   r   r   r   r      s
    zGuardedIterator.__init__c             C   s   | S )Nr   )r   r   r   r   r%      s    zGuardedIterator.__iter__c             C   sR   | j rttddd |  }| js4ttddd td| | jt| |S )Nziterated over closed app_iterr   )r   z3Application returned before it started the responsezapplication iterator items)	r8   r   r   r7   r9   r   r1   r2   r   )r   rvr   r   r   r6      s    
zGuardedIterator.nextc             C   s
  d| _ t| jdr| j  | jr| j\}}t| j}|jdtd}|dkrx8|D ]0\}}|	 }|dkrTt
|rTttd|  qTW |rttd nld	|  krd
k sn |dkr|dkrttd|  |rttd|  n |d k	r||krttd d S )NTr&   zcontent-length)r   i0  )Zexpireszcontent-locationz&entity header %r found in 304 responsez"304 responses must not have a bodyd         r   z.%r responses must have an empty content lengthz!%r responses must not have a bodyzGContent-Length and the number of bytes sent to the client do not match.)r8   hasattrr5   r&   r9   sumr1   getintlowerr   r   r   r   )r   status_codeheadersZ
bytes_sentZcontent_lengthkeyvaluer   r   r   r&      s2    



zGuardedIterator.closec             C   s0   | j s,yttd W n tk
r*   Y nX d S )Nz4Iterator was garbage collected before it was closed.)r8   r   r   	Exception)r   r   r   r   __del__   s
    zGuardedIterator.__del__N)r	   r
   r   r   r%   r6   r&   rI   r   r   r   r   r4      s
   r4   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  This middleware wraps an application and warns on common errors.
    Among other thing it currently checks for the following problems:

    -   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

    Detected errors are emitted using the standard Python :mod:`warnings`
    system and usually end up on :data:`stderr`.

    ::

        from werkzeug.contrib.lint import LintMiddleware
        app = LintMiddleware(app)

    :param app: the application to wrap
    c             C   s
   || _ d S )N)app)r   rK   r   r   r   r      s    zLintMiddleware.__init__c             C   s   t |tk	rttddd x(dD ] }||kr"ttd| dd q"W |d dkrbttd	dd |d
d}|r|d d dkrttd| dd |dd}|d d dkrttd| dd d S )Nz/WSGI environment is not a standard python dict.   )r   )	ZREQUEST_METHODZSERVER_NAMEZSERVER_PORTzwsgi.versionz
wsgi.inputzwsgi.errorszwsgi.multithreadzwsgi.multiprocesszwsgi.run_oncez%required environment key %r not foundr   zwsgi.version)r   r   z!environ is not a WSGI 1.0 environZSCRIPT_NAME r   /z+SCRIPT_NAME does not start with a slash: %rZ	PATH_INFOz)PATH_INFO does not start with a slash: %r)r   dictr   r   rA   )r   environrF   script_nameZ	path_infor   r   r   check_environ   s$    
zLintMiddleware.check_environc             C   sf  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 x|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 qW |d k	rLt|t	sLttddd t|}| | ||fS )Nstatusr   r   r   z Status code must be three digits)r   rL    zeInvalid value for status %r.  Valid status strings are three digits, a space and a status explanationr<   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   rB   r   listtupler   rC   
isinstancer   check_headers)r   rS   rE   exc_inforD   itemnamerG   r   r   r   check_start_response   s8    


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/zw/zw/z%weak etag indicator should be upcase.rL   )r   r   r   "zunquoted etag emitted.locationz*absolute URLs required for location header)rA   
startswithr   r   r   Znetloc)r   rE   r_   rb   r   r   r   rZ     s    


&

zLintMiddleware.check_headersc             C   s   t |trttddd d S )Nzapplication returned string.  Response will send character for character to the client which will kill the performance.  Return a list or iterable instead.r   )r   )rY   r   r   r   )r   app_iterr   r   r   check_iterator)  s    
zLintMiddleware.check_iteratorc                s   t |dkrttddd |r0ttddd |\}| t|d |d< t|d |d< t|d< g g   fdd	}||}| t	| S )
Nr   z"Two arguments to WSGI app required)r   z(No keyword arguments to WSGI app allowedz
wsgi.inputzwsgi.errorszwsgi.file_wrapperc                 s   t | dkr$ttdt |  dd |r4ttd | d d \}}t | dkrZ| d }nd }|||d d < t||| S )N)r   r   z0Invalid number of arguments: %s, expected 2 or 3r   )r   zno keyword arguments allowed.r   )r   r   r   r^   r.   )r!   kwargsrS   rE   r[   )r1   r9   r   start_responser   r   checking_start_responseC  s    
z8LintMiddleware.__call__.<locals>.checking_start_response)
r   r   r   rR   r   r'   r   rK   re   r4   )r   r!   rf   rP   rh   rd   r   )r1   r9   r   rg   r   r3   0  s     

zLintMiddleware.__call__N)
r	   r
   r   r   r   rR   r^   rZ   re   r3   r   r   r   r   rJ      s   $rJ   N)r   )r   Zurllib.parser   ImportErrorwarningsr   Zwerkzeug.datastructuresr   Zwerkzeug.httpr   Zwerkzeug.wsgir   Zwerkzeug._compatr   Warningr   r   r   objectr   r'   r.   r4   rJ   r   r   r   r   <module>   s"   
,?