
    'g8                    <   d Z ddlm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d	lmZ dd
lmZ ej"                  rddlmZ ddlmZ ddlmZ  G d de      Z G d de      ZefddZ G d d      Z G d d      Z G d d      Z G d d      Z G d d      Zy)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
    )annotationsN)TracebackType)urlparse)warn   )Headers)is_entity_header)FileWrapper)StartResponse)WSGIApplication)WSGIEnvironmentc                      e Zd ZdZy)WSGIWarningz Warning class for WSGI warnings.N__name__
__module____qualname____doc__     P/var/www/html/knws/venv/lib/python3.12/site-packages/werkzeug/middleware/lint.pyr   r   !       *r   r   c                      e Zd ZdZy)HTTPWarningz Warning class for HTTP warnings.Nr   r   r   r   r   r   %   r   r   r   c           	         t        |      |ur9t        | d|j                  dt        |      j                  dt        d       y y )Nz
 requires z, got .   
stacklevel)typer   r   r   )contextobjneeds      r   
check_typer$   )   sH    CykDMM#4F49;M;M:PPQR	
 r   c                  4    e Zd ZddZddZddZd	dZd
dZy)InputStreamc                    || _         y N_streamselfstreams     r   __init__zInputStream.__init__3   	    r   c                    t        |      dk(  rt        dt        d       n t        |      dk7  rt        dt        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,   argss     r   r3   zInputStream.read6   sY    t9>*  Y!^D
 !t||  $''r   c                    t        |      dk(  rt        dt        d       n,t        |      dk(  rt        dt        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   r1   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()'.)r2   r   r   	TypeErrorr*   readliner4   s     r   r8   zInputStream.readlineG   sf    t9>0	 Y!^O	 STT$t||$$d++r   c                    	 t        | j                        S # t        $ r  t        dt        d       t        d      cY S w xY w)Nz'wsgi.input' is not iterable.r   r   r   )iterr*   r7   r   r   r,   s    r   __iter__zInputStream.__iter__Z   s;    	%% 	0+!L8O	s    &A A c                \    t        dt        d       | j                  j                          y )Nz(The application closed the input stream!r   r   r   r   r*   closer;   s    r   r?   zInputStream.closea        7QRSr   N)r-   zt.IO[bytes]returnNone)r5   t.AnyrA   bytes)rA   zt.Iterator[bytes]rA   rB   )r   r   r   r.   r3   r8   r<   r?   r   r   r   r&   r&   2   s    (",&r   r&   c                  4    e Zd ZddZddZd	dZd
dZd	dZy)ErrorStreamc                    || _         y r(   r)   r+   s     r   r.   zErrorStream.__init__g   r/   r   c                \    t        d|t               | j                  j                  |       y )Nzwsgi.error.write())r$   strr*   writer,   ss     r   rK   zErrorStream.writej   s!    'C01r   c                8    | j                   j                          y r(   )r*   flushr;   s    r   rO   zErrorStream.flushn   s    r   c                4    |D ]  }| j                  |        y r(   )rK   )r,   seqlines      r   
writelineszErrorStream.writelinesq   s     	DJJt	r   c                \    t        dt        d       | j                  j                          y )Nz(The application closed the error stream!r   r   r>   r;   s    r   r?   zErrorStream.closeu   r@   r   N)r-   z	t.IO[str]rA   rB   )rM   rJ   rA   rB   rE   )rQ   zt.Iterable[str]rA   rB   )r   r   r   r.   rK   rO   rS   r?   r   r   r   rG   rG   f   s    r   rG   c                      e Zd ZddZddZy)GuardedWritec                     || _         || _        y r(   )_write_chunks)r,   rK   chunkss      r   r.   zGuardedWrite.__init__{   s    r   c                    t        d|t               | j                  |       | j                  j	                  t        |             y )Nzwrite())r$   rD   rX   rY   appendr2   rL   s     r   __call__zGuardedWrite.__call__   s/    9a'ACF#r   N)rK   zt.Callable[[bytes], object]rZ   	list[int]rA   rB   )rM   rD   rA   rB   )r   r   r   r.   r]   r   r   r   rV   rV   z   s    $r   rV   c                  D    e Zd Z	 	 	 	 	 	 	 	 ddZddZd	dZd
dZd
dZy)GuardedIteratorc                p    || _         t        |      j                  | _        d| _        || _        || _        y )NF)	_iteratorr:   __next___nextclosedheaders_setrZ   )r,   iteratorrf   rZ   s       r   r.   zGuardedIterator.__init__   s2     "(^,,
&r   c                    | S r(   r   r;   s    r   r<   zGuardedIterator.__iter__   s    r   c                   | j                   rt        dt        d       | j                         }| j                  st        dt        d       t        d|t               | j                  j                  t        |             |S )Nz Iterated over closed 'app_iter'.r   r   z8The application returned before it started the response.zapplication iterator items)
re   r   r   rd   rf   r$   rD   rZ   r\   r2   )r,   rvs     r   rc   zGuardedIterator.__next__   se    ;;3[QOZZ\J 	/U;3r7#	r   c                z   d| _         t        | j                  d      r| j                  j                          | j                  r| j                  \  }}t        | j                        }|j                  dt              }|dk(  rW|D ]<  \  }}|j                         }|dvst        |      s't        d|dt        d	
       > |rt        dt        d	
       y y d|cxk  rdk  sn |dk(  r3|dk7  rt        | dt        d	
       |rt        | dt        d	
       y y |||k7  rt        dt        d	
       y y y y )NTr?   zcontent-length)r    i0  )expireszcontent-locationzEntity header z found in 304 response.r   r   z#304 responses must not have a body.d         r   z- responses must have an empty content length.z  responses must not have a body.zGContent-Length and the number of bytes sent to the client do not match.)re   hasattrrb   r?   rf   sumrZ   getintlowerr	   r   r   r   )r,   status_codeheaders
bytes_sentcontent_lengthkey_values          r   r?   zGuardedIterator.close   s_   4>>7+NN  "#'#3#3 KT[[)J$[[)9[DNc!#* 	KC))+C"AAFVG ,SG3JK''(	 =##$  )c)[C-?!Q&&-'TU##$
 &-'GH##$   +*0L, 	 1M+G r   c                b    | j                   s	 t        dt        d       y y # t        $ r Y y w xY w)Nz4Iterator was garbage collected before it was closed.r   r   )re   r   r   	Exceptionr;   s    r   __del__zGuardedIterator.__del__   s8    {{J    s   " 	..N)rg   t.Iterable[bytes]rf   tuple[int, Headers]rZ   r^   rA   rB   )rA   r`   )rA   rD   rE   )r   r   r   r.   r<   rc   r?   r}   r   r   r   r`   r`      sB    
#
 )
 	

 

"/b	r   r`   c                  P    e Zd ZdZd	dZd
dZ	 	 	 	 	 	 	 	 ddZddZddZddZ	y)LintMiddlewarea  Warns about common errors in the WSGI and HTTP behavior of the
    server and wrapped application. Some of the issues it checks are:

    -   invalid status codes
    -   non-bytes 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                    || _         y r(   )app)r,   r   s     r   r.   zLintMiddleware.__init__   s	    r   c                   t        |      t        urt        dt        d       dD ]  }||vst        d|dt        d        |d   d	k7  rt        d
t        d       |j	                  dd      }|j	                  dd      }|r|d   dk7  rt        d|t        d       |r|d   dk7  rt        d|t        d       y y y )Nz/WSGI environment is not a standard Python dict.   r   )	REQUEST_METHODSERVER_NAMESERVER_PORTwsgi.version
wsgi.inputwsgi.errorszwsgi.multithreadzwsgi.multiprocesszwsgi.run_oncezRequired environment key z
 not foundr   r   )r1   r   z"Environ is not a WSGI 1.0 environ.SCRIPT_NAME 	PATH_INFOr   /z+'SCRIPT_NAME' does not start with a slash: z)'PATH_INFO' does not start with a slash: )r    dictr   r   rr   )r,   environry   script_name	path_infos        r   check_environzLintMiddleware.check_environ   s    =$A


 	C '!/wjA 	" >"f,5{qQkk-4KKR0	;q>S0=k_M 1,;I=I -9r   c                F   t        d|t               |j                  d d      d   }t        |      dk7  s|j	                         st        dt        d       t        |      dk  s|d   dk7  rt        d	|d
t        d       t        |      }|dk  rt        dt        d       t        |      t        urt        dt        d       |D ]  }t        |      t        ust        |      dk7  rt        dt        d       |\  }}t        |      t        ust        |      t        urt        dt        d       |j                         dk(  st        dt        d        |"t        |t              st        dt        d       t        |      }	| j                  |	       ||	fS )Nstatusr1   r   r   z!Status code must be three digits.r   r    zInvalid value for status zJ. Valid status strings are three digits, a space and a status explanation.rm   zStatus code < 100 detected.zHeader list is not a list.r   z#Header items must be 2-item tuples.z'Header keys and values must be strings.zFThe status header is not supported due to conflicts with the CGI spec.zInvalid value for exc_info.)r$   rJ   splitr2   	isdecimalr   r   rs   r    listtuplert   
isinstancer   check_headers)
r,   r   rv   exc_infostatus_code_strru   itemnamevalueheaders_objs
             r   check_start_responsez#LintMiddleware.check_start_response)  s    	8VS) ,,tQ/21$O,E,E,G4kaPv;?fQi3.+F: 6= =	 /*.J=$-{qI 	DDz&#d)q.:KTUVKD%Dz$U3(>={WX zz|x'4 		  
8U(C.Jg&;'K''r   c                ^   |j                  d      }|^|j                  d      r(|j                  d      rt        dt        d       |dd  }|d d |d	d  cxk(  rd
k(  sn t        dt        d       |j                  d      }|)t	        |      j
                  st        dt        d       y y y )Netag)zW/w/r   z)Weak etag indicator should be upper case.r   r   r   r1   "zUnquoted etag emitted.locationz+Absolute URLs required for location header.)rr   
startswithr   r   r   netloc)r,   rv   r   r   s       r   r   zLintMiddleware.check_headers]  s    {{6"|,??4(C##$ ABx!HRS	0S0-{qI;;z*H%,,A  -  r   c                J    t        |t              rt        dt        d       y y )NzThe application returned a string. The response will send one character at a time to the client, which will kill performance. Return a list or iterable instead.r   r   )r   rJ   r   r   )r,   app_iters     r   check_iteratorzLintMiddleware.check_iteratorx  s&    h$6  %r   c                    t        |      dk7  rt        dt        d       |rt        dt        d       |d   }|d    j                  |       t	        |d         |d<   t        |d         |d<   t        |d	<   g g 	 	 	 	 	 	 d fd
} j                  |t        j                  d|            } j                  |       t        |t        j                  t        t        t        f               S )Nr   zA WSGI app takes two arguments.r   z+A WSGI app does not take keyword arguments.r   r1   r   r   zwsgi.file_wrapperc                    t        |       dvrt        dt        |        dt        d       |rt        dt        d       | d   }| d   }t        |       d	k(  r| d   nd }j                  |||      d d  t	         |||            S )
N>   r   r   zInvalid number of arguments: z, expected 2 or 3.r   r   z1'start_response' does not take keyword arguments.r   r1   r   )r2   r   r   r   rV   )	r5   kwargsr   rv   r   rZ   rf   r,   start_responses	        r   checking_start_responsez8LintMiddleware.__call__.<locals>.checking_start_response  s     4y&3CI;>PQ  G  q'F-1!WG t9>Qt  "66vwQKNvw I6RRr   r   )r5   rC   r   rC   rA   zt.Callable[[bytes], None])r2   r   r   r   r&   rG   r
   r   tcastr   r`   r   rs   r   )	r,   r5   r   r   r   r   rZ   rf   r   s	   `     @@@r   r]   zLintMiddleware.__call__  s
   t9>2KAN={WX $(7(,Q7# +GL,A B!,W]-C!D (3#$#%	S	S$)	S&	S 	S4 88GQVVO=T%UVH%affU3<0+>
 	
r   N)r   r   rA   rB   )r   r   rA   rB   )r   rJ   rv   zlist[tuple[str, str]]r   z?None | tuple[type[BaseException], BaseException, TracebackType]rA   r   )rv   r   rA   rB   )r   r~   rA   rB   )r5   rC   r   rC   rA   r~   )
r   r   r   r   r.   r   r   r   r   r]   r   r   r   r   r      sN    ,*X2(2( '2( T	2(
 
2(h65
r   r   )r!   rJ   r"   objectr#   r    rA   rB   ) r   
__future__r   typingr   typesr   urllib.parser   warningsr   datastructuresr   httpr	   wsgir
   TYPE_CHECKING_typeshed.wsgir   r   r   Warningr   r   rJ   r$   r&   rG   rV   r`   r   r   r   r   <module>r      s    #   !  $ # ??,..+' ++' + 8; 
1 1h ($ $[ [|T
 T
r   