
    2Bf6              	       T   d 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ededej2                  ddf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
    N)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__     X/var/www/highfloat_scraper/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   contextobjneedreturnc           	          t        |      |ur9t        | d|j                  dt        |      j                  dt        d       y y )Nz
 requires z, got .   
stacklevel)typer   r   r   )r   r   r   s      r   
check_typer$   &   sH    CykDMM#4F49;M;M:PPQR	
 r   c                       e Zd Zdej                  ddfdZdej                  defdZdej                  defdZ	dej                  e   fdZd
d	Zy)InputStreamstreamr   Nc                     || _         y N_streamselfr'   s     r   __init__zInputStream.__init__0   	    r   argsc                     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-   r0   s     r   r4   zInputStream.read3   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!   r2   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()'.)r3   r   r   	TypeErrorr+   readliner5   s     r   r8   zInputStream.readlineD   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__W   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.close^        7QRSr   r   N)r   r   r   tBinaryIOr.   Anybytesr4   r8   Iteratorr<   r?   r   r   r   r&   r&   /   sa    qzz d (!%% (E (",aee , ,&!**U+ r   r&   c                   z    e Zd Zdej                  ddfdZdeddfdZddZdej                  e   ddfd	Z
dd
Zy)ErrorStreamr'   r   Nc                     || _         y r)   r*   r,   s     r   r.   zErrorStream.__init__d   r/   r   sc                 \    t        d|t               | j                  j                  |       y )Nzwsgi.error.write())r$   strr+   writer-   rJ   s     r   rM   zErrorStream.writeg   s!    'C01r   c                 8    | j                   j                          y r)   )r+   flushr;   s    r   rP   zErrorStream.flushk   s    r   seqc                 4    |D ]  }| j                  |        y r)   )rM   )r-   rQ   lines      r   
writelineszErrorStream.writelinesn   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.closer   r@   r   rA   )r   r   r   rB   TextIOr.   rL   rM   rP   IterablerT   r?   r   r   r   rH   rH   c   sQ    qxx D s t ajjo $ r   rH   c                   j    e Zd Zdej                  egdf   dej                  e   ddfdZdeddfdZ	y)GuardedWriterM   Nchunksr   c                      || _         || _        y r)   )_write_chunks)r-   rM   rZ   s      r   r.   zGuardedWrite.__init__x   s    r   rJ   c                     t        d|t               | j                  |       | j                  j	                  t        |             y )Nzwrite())r$   rE   r\   r]   appendr3   rN   s     r   __call__zGuardedWrite.__call__|   s/    9a'ACF#r   )
r   r   r   rB   CallablerE   Listintr.   r`   r   r   r   rY   rY   w   sG    ajj%$7  QU $% $D $r   rY   c                       e Zd Zdej                  e   dej                  eef   dej                  e   ddfdZ
ddZdefdZdd	Zdd
Zy)GuardedIteratoriteratorheaders_setrZ   r   Nc                 p    || _         t        |      j                  | _        d| _        || _        || _        y )NF)	_iteratorr:   __next___nextclosedrg   rZ   )r-   rf   rg   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)
rl   r   r   rk   rg   r$   rE   rZ   r_   r3   )r-   rvs     r   rj   zGuardedIterator.__next__   se    ;;3[QOZZ\J 	/U;3r7#	r   c                 f   d| _         t        | j                  d      r| j                  j                          | j                  r| j                  \  }}t        | j                        }|j                  dt              }|dk(  rS|D ]:  \  }}|j                         }|dvst        |      s't        d|dt               < |rt        d	t               y y d
|cxk  rdk  sn |dk(  r/|dk7  rt        | dt               |rt        | dt               y y |||k7  rt        dt               y y y y )NTr?   zcontent-length)r#   i0  )expireszcontent-locationzEntity header z found in 304 response.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.)rl   hasattrri   r?   rg   sumrZ   getrc   lowerr   r   r   r   )r-   status_codeheaders
bytes_sentcontent_lengthkey_values          r   r?   zGuardedIterator.close   sC   4>>7+NN  "#'#3#3 KT[[)J$[[)9[DNc!#* KC))+C"AAFVG ,SG3JK[ >L )c)[C-?!Q&&-'TU# K=(HI;W +*0L, 1M+1 r   c                 ^    | j                   s	 t        dt               y y # t        $ r Y y w xY w)Nz4Iterator was garbage collected before it was closed.)rl   r   r   	Exceptionr;   s    r   __del__zGuardedIterator.__del__   s4    {{JK 
  s     	,,)r   re   rA   )r   r   r   rB   rW   rE   Tuplerc   r   rb   r.   r<   rj   r?   r   r   r   r   re   re      sg    
**U#
 WWS'\*
 s	

 

% "#Jr   re   c            
       r   e Zd ZdZddZddZdedej                  ej                  eef      dej                  ej                  ej                  e   eef      dej                  eef   fd	Zdeddfd
Zdej$                  e   ddfdZdej*                  dej*                  dej$                  e   f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)
    r   Nc                     || _         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   )r2   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   rw   )r-   environr}   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   statusrz   exc_infoc                 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 )Nr   r2   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.rr   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$   rL   splitr3   isdigitr   r   rc   r#   listtuplerx   
isinstancer   check_headers)	r-   r   rz   r   status_code_strry   itemnamevalues	            r   check_start_responsez#LintMiddleware.check_start_response  s    	8VS) ,,tQ/21$O,C,C,E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'"7#G##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   r2   "zUnquoted etag emitted.locationz+Absolute URLs required for location header.)rw   
startswithr   r   r   netloc)r-   rz   r   r   s       r   r   zLintMiddleware.check_headersN  s    {{6"|,??4(C##$ ABx!HRS	0S0-{qI;;z*H%,,A  -  r   app_iterc                 J    t        |t              rt        dt        d       y y )NzThe application returned a bytestring. 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   rE   r   r   )r-   r   s     r   check_iteratorzLintMiddleware.check_iteratori  s&    h&6  'r   r0   kwargsc                 r    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
t        j                  dt        j                  dt        j                  t        gd f   f fd} j                  |t        j                  d|            } j                  |       t        |t        j                  t        j                  t         t"        f               S )Nr   zA WSGI app takes two arguments.r!   z+A WSGI app does not take keyword arguments.r   r2   r   r   zwsgi.file_wrapperr0   r   r   c                     t        |       dvrt        dt        |        dt        d       |rt        dt               | 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   r2   r    )r3   r   r   r   rY   )	r0   r   r   rz   r   rZ   rg   r-   start_responses	        r   checking_start_responsez8LintMiddleware.__call__.<locals>.checking_start_response  s     4y&3CI;>PQ  H+Vq'F15aG  INa  "66vwQKNvw I6RRr   r
   )r3   r   r   r   r&   rH   r	   rB   rD   ra   rE   r   castr   re   r   rc   r   )	r-   r0   r   r   r   r   rZ   rg   r   s	   `     @@@r   r`   zLintMiddleware.__call__s  s%   t9>2KAN={WX &*!W*.q'7# +GL,A B!,W]-C!D (3#$%' 	S55	S$%EE	SZZ&	S 	S, 88GQVVO=T%UVH%affQWWS'\2K@&
 	
r   )r   r   r   N)r   r   r   N)r   r   r   r   r.   r   rL   rB   rb   r   OptionalTypeBaseExceptionr   rc   r   r   r   rW   rE   r   rD   r`   r   r   r   r   r      s    ,*X4$4$ S)*4$ **GGAFF=)=-GH
	4$ 
g	4$lW  6qzz%'8 T 1
aee 1
quu 1
E9J 1
r   r   ) r   typingrB   typesr   urllib.parser   warningsr   datastructuresr   httpr   wsgir	   TYPE_CHECKING_typeshed.wsgir
   r   r   Warningr   r   rL   objectr   r$   r&   rH   rY   re   r   r   r   r   <module>r      s      !  $ # ??,..+' ++' + := 
 
& 
 
 
1 1h ($ $M M`R
 R
r   