Ë
    òT•j¼:  ã                   ó*  — d Z dgZddlZddlZddlZ ej
                  d«      Z ej
                  d«      Z G d„ de«      Z	d„ Z
d	„ Zd
„ Z G d„ d«      Z G d„ d«      Z G d„ d«      Z G d„ d«      Z G d„ d«      Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zy)a&  
Middleware to check for obedience to the WSGI specification.

Some of the things this checks:

* Signature of the application and start_response (including that
  keyword arguments are not used).

* Environment checks:

  - Environment is a dictionary (and not a subclass).

  - That all the required keys are in the environment: REQUEST_METHOD,
    SERVER_NAME, SERVER_PORT, wsgi.version, wsgi.input, wsgi.errors,
    wsgi.multithread, wsgi.multiprocess, wsgi.run_once

  - That HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH are not in the
    environment (these headers should appear as CONTENT_LENGTH and
    CONTENT_TYPE).

  - Warns if QUERY_STRING is missing, as the cgi module acts
    unpredictably in that case.

  - That CGI-style variables (that don't contain a .) have
    (non-unicode) string values

  - That wsgi.version is a tuple

  - That wsgi.url_scheme is 'http' or 'https' (@@: is this too
    restrictive?)

  - Warns if the REQUEST_METHOD is not known (@@: probably too
    restrictive).

  - That SCRIPT_NAME and PATH_INFO are empty or start with /

  - That at least one of SCRIPT_NAME or PATH_INFO are set.

  - That CONTENT_LENGTH is a positive integer.

  - That SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
    be '/').

  - That wsgi.input has the methods read, readline, readlines, and
    __iter__

  - That wsgi.errors has the methods flush, write, writelines

* The status is a string, contains a space, starts with an integer,
  and that integer is in range (> 100).

* That the headers is a list (not a subclass, not another kind of
  sequence).

* That the items of the headers are tuples of strings.

* That there is no 'status' header (that is used in CGI, but not in
  WSGI).

* That the headers don't contain newlines or colons, end in _ or -, or
  contain characters codes below 037.

* That Content-Type is given if there is content (CGI often has a
  default content type, but WSGI does not).

* That no Content-Type is given when there is no content (@@: is this
  too restrictive?)

* That the exc_info argument to start_response is a tuple or None.

* That all calls to the writer are with strings, and no other methods
  on the writer are accessed.

* That wsgi.input is used properly:

  - .read() is called with exactly one argument

  - That it returns a string

  - That readline, readlines, and __iter__ return strings

  - That .close() is not called

  - No other methods are provided

* That wsgi.errors is used properly:

  - .write() and .writelines() is called with a string

  - That .close() is not called, and no other methods are provided.

* The response iterator:

  - That it is not a string (it should be a list of a single string; a
    string will work, but perform horribly).

  - That .__next__() returns a string

  - That the iterator is not iterated over until start_response has
    been called (that can signal either a server or application
    error).

  - That .close() is called (doesn't raise exception, only prints to
    sys.stderr, because we only know it isn't called when the object
    is garbage collected).
Ú	validatoré    Nz^[a-zA-Z][a-zA-Z0-9\-_]*$z[\000-\037]c                   ó   — e Zd ZdZy)ÚWSGIWarningz:
    Raised in response to WSGI-spec-related warnings
    N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú'/usr/lib/python3.12/wsgiref/validate.pyr   r   y   s   „ òr   r   c                 ó   — | st        |Ž ‚y ©N)ÚAssertionError)ÚcondÚargss     r   Úassert_r   ~   s   € ÙÜ˜dÐ#Ð#ð r   c                 óp   — t        | «      t        u r| S t        dj                  |t	        | «      «      «      ‚)Nz!{0} must be of type str (got {1}))ÚtypeÚstrr   ÚformatÚrepr)ÚvalueÚtitles     r   Úcheck_string_typer   ‚   s6   € ÜˆUƒ|”sÑØˆÜ
Ø+×2Ñ2°5¼$¸u»+ÓFóHð Hr   c                 ó   ‡ — ˆ fd„}|S )a®  
    When applied between a WSGI server and a WSGI application, this
    middleware will check for WSGI compliance on a number of levels.
    This middleware does not modify the request or response in any
    way, but will raise an AssertionError if anything seems off
    (except for a failure to close the application iterator, which
    will be printed to stderr -- there's no way to raise an exception
    at that point).
    c                  ó0  •‡‡— t        t        | «      dk(  d«       t        | d«       | \  }Št        |«       g Šˆˆfd„}t        |d   «      |d<   t	        |d   «      |d<    ‰||«      }t        |d uxr |dk7  d«       t        |«       t        |‰«      S )	Né   zTwo arguments requiredúNo keyword arguments allowedc                  óL  •— t        t        | «      dk(  xs t        | «      dk(  d| ›�«       t        | d«       | d   }| d   }t        | «      dk(  r| d   }nd }t        |«       t        |«       t	        ||«       t        |«       ‰j                  d «       t         ‰| Ž «      S )Nr   é   zInvalid number of arguments: r   r   é   )r   ÚlenÚcheck_statusÚcheck_headersÚcheck_content_typeÚcheck_exc_infoÚappendÚWriteWrapper)r   ÚkwÚstatusÚheadersÚexc_infoÚstart_responseÚstart_response_starteds        €€r   Ústart_response_wrapperz;validator.<locals>.lint_app.<locals>.start_response_wrapperŸ   s¡   ø€ Ü”C˜“I ‘NÒ4¤c¨$£i°1¡nøÙ59Ð;ô>ä˜�FÐ:Ô;Ø˜!‘WˆFØ˜1‘gˆGÜ�4‹y˜AŠ~Ø ™7‘à�ä˜Ô Ü˜'Ô"Ü˜v wÔ/Ü˜8Ô$à"×)Ñ)¨$Ô/Ü¡°Ð 5Ó6Ð6r   ú
wsgi.inputúwsgi.errorsFz>The application must return an iterator, if only an empty list)r   r"   Úcheck_environÚInputWrapperÚErrorWrapperÚcheck_iteratorÚIteratorWrapper)r   r)   Úenvironr/   Úiteratorr-   r.   Úapplications        @@€r   Úlint_appzvalidator.<locals>.lint_app”   s®   ú€ Ü”�D“	˜Q‘Ð 8Ô9Ü�B�Ð6Ô7Ø"&Ñˆ�ä�gÔð "$Ðõ	7ô& !-¨W°\Ñ-BÓ Cˆ�ÑÜ!-¨g°mÑ.DÓ!Eˆ�Ñá˜wÐ(>Ó?ˆÜ� Ð$Ò:¨°UÑ):ØLô	Nô 	�xÔ ä˜xÐ)?Ó@Ð@r   r
   )r9   r:   s   ` r   r   r   ˆ   s   ø€ ô'AðR €Or   c                   ó0   — e Zd Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zy)r3   c                 ó   — || _         y r   )Úinput)ÚselfÚ
wsgi_inputs     r   Ú__init__zInputWrapper.__init__Á   s	   € Øˆ�
r   c                 óš   — t        t        |«      dk(  «        | j                  j                  |Ž }t        t	        |«      t
        u «       |S ©Nr!   )r   r"   r=   Úreadr   Úbytes©r>   r   Úvs      r   rC   zInputWrapper.readÄ   s<   € Ü”�D“	˜Q‘ÔØˆD�J‰J�O‰O˜TÐ"ˆÜ”�Q“œ5Ð Ô!Øˆr   c                 óš   — t        t        |«      dk  «        | j                  j                  |Ž }t        t	        |«      t
        u «       |S rB   )r   r"   r=   Úreadliner   rD   rE   s      r   rH   zInputWrapper.readlineÊ   s>   € Ü”�D“	˜Q‘ÔØˆD�J‰J×Ñ Ð&ˆÜ”�Q“œ5Ð Ô!Øˆr   c                 óÜ   — t        t        |«      dk  «        | j                  j                  |Ž }t        t	        |«      t
        u «       |D ]  }t        t	        |«      t        u «       Œ |S rB   )r   r"   r=   Ú	readlinesr   ÚlistrD   )r>   r   ÚlinesÚlines       r   rJ   zInputWrapper.readlinesÐ   s^   € Ü”�D“	˜Q‘ÔØ$�—
‘
×$Ñ$ dÐ+ˆÜ”�U“œtÐ#Ô$Øò 	)ˆDÜ”D˜“J¤%Ð'Õ(ð	)àˆr   c              #   ó`   K  — | j                  «       x}r|–— | j                  «       x}rŒy y ­wr   )rH   )r>   rM   s     r   Ú__iter__zInputWrapper.__iter__Ø   s/   è ø€ Ø—m‘m“oÐ%ˆdÐ%ØŠJð —m‘m“oÐ%ˆdÓ%ùs   ‚).¬.c                 ó   — t        dd«       y )Nr   z input.close() must not be called©r   ©r>   s    r   ÚclosezInputWrapper.closeÜ   s   € Ü�Ð5Õ6r   N)	r   r   r   r@   rC   rH   rJ   rO   rS   r
   r   r   r3   r3   ¿   s    „ ò òòòòó7r   r3   c                   ó*   — e Zd Zd„ Zd„ Zd„ Zd„ Zd„ Zy)r4   c                 ó   — || _         y r   )Úerrors)r>   Úwsgi_errorss     r   r@   zErrorWrapper.__init__á   ó	   € Ø!ˆ�r   c                 ón   — t        t        |«      t        u «       | j                  j	                  |«       y r   )r   r   r   rV   Úwrite©r>   Úss     r   rZ   zErrorWrapper.writeä   s$   € Ü”�Q“œ3�ÔØ�‰×Ñ˜!Õr   c                 ó8   — | j                   j                  «        y r   )rV   ÚflushrR   s    r   r^   zErrorWrapper.flushè   s   € Ø�‰×ÑÕr   c                 ó4   — |D ]  }| j                  |«       Œ y r   )rZ   )r>   ÚseqrM   s      r   Ú
writelineszErrorWrapper.writelinesë   s   € Øò 	ˆDØ�J‰J�tÕñ	r   c                 ó   — t        dd«       y )Nr   z!errors.close() must not be calledrQ   rR   s    r   rS   zErrorWrapper.closeï   s   € Ü�Ð6Õ7r   N)r   r   r   r@   rZ   r^   ra   rS   r
   r   r   r4   r4   ß   s   „ ò"òòòó8r   r4   c                   ó   — e Zd Zd„ Zd„ Zy)r(   c                 ó   — || _         y r   )Úwriter)r>   Úwsgi_writers     r   r@   zWriteWrapper.__init__ô   rX   r   c                 óZ   — t        t        |«      t        u «       | j                  |«       y r   )r   r   rD   re   r[   s     r   Ú__call__zWriteWrapper.__call__÷   s   € Ü”�Q“œ5Ð Ô!Ø�‰�A�r   N)r   r   r   r@   rh   r
   r   r   r(   r(   ò   s   „ ò"ór   r(   c                   ó   — e Zd Zd„ Zd„ Zy)ÚPartialIteratorWrapperc                 ó   — || _         y r   ©r8   )r>   Úwsgi_iterators     r   r@   zPartialIteratorWrapper.__init__ý   s	   € Ø%ˆ�r   c                 ó.   — t        | j                  d «      S r   )r6   r8   rR   s    r   rO   zPartialIteratorWrapper.__iter__   s   € ä˜tŸ}™}¨dÓ3Ð3r   N)r   r   r   r@   rO   r
   r   r   rj   rj   û   s   „ ò&ó4r   rj   c                   ó*   — e Zd Zd„ Zd„ Zd„ Zd„ Zd„ Zy)r6   c                 óN   — || _         t        |«      | _        d| _        || _        y )NF)Úoriginal_iteratorÚiterr8   ÚclosedÚcheck_start_response)r>   rm   rt   s      r   r@   zIteratorWrapper.__init__  s%   € Ø!.ˆÔÜ˜]Ó+ˆŒØˆŒØ$8ˆÕ!r   c                 ó   — | S r   r
   rR   s    r   rO   zIteratorWrapper.__iter__  s   € Øˆr   c                 óò   — t        | j                   d«       t        | j                  «      }t	        |«      t
        urt        dd|›d�«       | j                  �t        | j                  d«       d | _        |S )NzIterator read after closedFz!Iterator yielded non-bytestring (ú)zjThe application returns and we started iterating over its body, but start_response has not yet been called)r   rs   Únextr8   r   rD   rt   )r>   rF   s     r   Ú__next__zIteratorWrapper.__next__  si   € Ü�D—K‘K�Ø(ô	*ä�—‘ÓˆÜ�‹7œ%ÑÜ‘EÂQÐHÔIØ×$Ñ$Ð0Ü�D×-Ñ-Ø|ô~à(,ˆDÔ%Øˆr   c                 ót   — d| _         t        | j                  d«      r| j                  j                  «        y y )NTrS   )rs   Úhasattrrq   rS   rR   s    r   rS   zIteratorWrapper.close  s0   € ØˆŒÜ�4×)Ñ)¨7Ô3Ø×"Ñ"×(Ñ(Õ*ð 4r   c                 ó†   — | j                   st        j                  j                  d«       t	        | j                   d«       y )Nz/Iterator garbage collected without being closed)rs   ÚsysÚstderrrZ   r   rR   s    r   Ú__del__zIteratorWrapper.__del__   s0   € Ø�{Š{Ü�J‰J×ÑØAôCä�—‘Ø=õ	?r   N)r   r   r   r@   rO   ry   rS   r   r
   r   r   r6   r6     s   „ ò9òò
ò+ó
?r   r6   c                 ób  — t        t        | «      t        u dt        | «      ›d| ›d�«       dD ]  }t        || v d|›�«       Œ dD ]  }t        || vd|›d|d	d  ›d
�«       Œ d| vrt        j                  dt
        «       | j                  «       D ]>  }d|v rŒt        t        | |   «      t        u d|›dt        | |   «      ›d| |   ›d�«       Œ@ t        t        | d   «      t        u d| d   ›d�«       t        | d   dv d| d   z  «       t        | d   «       t        | d   «       | d   dvr t        j                  d| d   z  t
        «       t        | j                  d«       xs | d   j                  d«      d| d   z  «       t        | j                  d«       xs | d   j                  d«      d| d   z  «       | j                  d «      r!t        t        | d    «      d!k\  d"| d    z  «       | j                  d«      st        d| v d#«       t        | j                  d«      dk7  d$«       y )%Nz&Environment is not of the right type: z (environment: rw   )	ÚREQUEST_METHODÚSERVER_NAMEÚSERVER_PORTúwsgi.versionr0   r1   zwsgi.multithreadzwsgi.multiprocesszwsgi.run_oncez"Environment missing required key: )ÚHTTP_CONTENT_TYPEÚHTTP_CONTENT_LENGTHz%Environment should not have the key: z (use é   z	 instead)ÚQUERY_STRINGz’QUERY_STRING is not in the WSGI environment; the cgi module will use sys.argv when this variable is missing, so application errors are more likelyú.zEnvironmental variable z is not a string: z	 (value: r„   z wsgi.version should be a tuple (zwsgi.url_scheme)ÚhttpÚhttpszwsgi.url_scheme unknown: %rr0   r1   r�   )ÚGETÚHEADÚPOSTÚOPTIONSÚPATCHÚPUTÚDELETEÚTRACEzUnknown REQUEST_METHOD: %rÚSCRIPT_NAMEú/z$SCRIPT_NAME doesn't start with /: %rÚ	PATH_INFOz"PATH_INFO doesn't start with /: %rÚCONTENT_LENGTHr   zInvalid CONTENT_LENGTH: %rzgOne of SCRIPT_NAME or PATH_INFO are required (PATH_INFO should at least be '/' if SCRIPT_NAME is empty)zOSCRIPT_NAME cannot be '/'; it should instead be '', and PATH_INFO should be '/')r   r   ÚdictÚwarningsÚwarnr   Úkeysr   ÚtupleÚcheck_inputÚcheck_errorsÚgetÚ
startswithÚint)r7   Úkeys     r   r2   r2   '  s}  € ÜŒD�‹MœTÑ!ä��=š'ð	#ô$ð!ò =ˆô 	��w‘Ù69Ð;õ	=ð	=ð <ò 1ˆÜ�˜7Ñ"â"% s¨1¨2¢wð0õ	1ð1ð
 ˜WÑ$Ü�‰ð4ô ô		ð �|‰|‹~ò 7ˆØ�#‰:àÜ”�W˜S‘\Ó"¤cÑ)â”D˜ ™Õ&¨°«ð6õ	7ð	7ô ŒD�˜Ñ(Ó)¬UÑ2Ø18¸Ó1HÐJôLäˆGÐ%Ñ&Ð*;Ð;Ø%¨Ð0AÑ(BÑBôDô �˜Ñ%Ô&Ü�˜Ñ'Ô(ð ÐÑ ð )Mñ Mä�‰Ø(¨7Ð3CÑ+DÑDÜô	ô �—‘˜MÓ*Ð*ò 6Ø�}Ñ%×0Ñ0°Ó5Ø.°¸Ñ1GÑGôIô �—‘˜KÓ(Ð(ò 4Ø�{Ñ#×.Ñ.¨sÓ3Ø,¨w°{Ñ/CÑCôEð ‡{�{Ð#Ô$Ü”�GÐ,Ñ-Ó.°!Ñ3Ø(¨7Ð3CÑ+DÑDô	Fð �;‰;�}Ô%Ü�˜wÐ&ð>ô	?ô ˆG�K‰K˜Ó&¨#Ñ-ð	"õ#r   c                 óJ   — dD ]  }t        t        | |«      d| ›d|›�«       Œ  y )N)rC   rH   rJ   rO   zwsgi.input (ú) doesn't have the attribute ©r   r{   )r?   Úattrs     r   r�   r�   h  s,   € Ø=ò "ˆÜ”˜
 DÔ)â™4ð!õ	"ñ"r   c                 óJ   — dD ]  }t        t        | |«      d| ›d|›�«       Œ  y )N)r^   rZ   ra   zwsgi.errors (r¤   r¥   )rW   r¦   s     r   rž   rž   n  s,   € Ø0ò #ˆÜ”˜ TÔ*â™Dð"õ	#ñ#r   c                 ó  — t        | d«      } | j                  d d«      d   }t        t        |«      dk(  d|z  «       t	        |«      }t        |dk\  d|z  «       t        | «      dk  s| d   d	k7  rt        j                  d
| z  t        «       y y )NÚStatusr!   r   r    z)Status codes must be three characters: %réd   zStatus code is invalid: %ré   ú zjThe status string (%r) should be a three-digit integer followed by a single space and a status explanation)r   Úsplitr   r"   r¡   r™   rš   r   )r*   Ústatus_codeÚ
status_ints      r   r#   r#   t  s—   € Ü˜v xÓ0€Fà—,‘,˜t QÓ'¨Ñ*€KÜŒC�Ó Ñ!Ø3°kÑAôCä�[Ó!€JÜˆJ˜#ÑÐ;¸jÑHÔIÜ
ˆ6ƒ{�Q‚˜& ™) sÒ*Ü�‰ðBàñä!õ	#ð +r   c           
      óÖ  — t        t        | «      t        u d| ›dt        | «      ›�«       | D �]9  }t        t        |«      t        u d|›dt        |«      ›�«       t        t	        |«      dk(  «       |\  }}t        |d«      }t        |d«      }t        |j                  «       dk7  d	|z  «       t        d
|vxr d|vd|z  «       t        t        j                  |«      d|z  «       t        |j                  d«       xr |j                  d«       d|z  «       t        j                  |«      s�Œt        dd|›dt        j                  |«      j                  d«      ›d�«       �Œ< y )Nz	Headers (z) must be of type list: zIndividual headers (z) must be of type tuple: r   úHeader namezHeader valuer*   zyThe Status header cannot be used; it conflicts with CGI script, and HTTP status is not given through headers (value: %r).ú
ú:z,Header names may not contain ':' or '\n': %rzBad header name: %rú-Ú_z#Names may not end in '-' or '_': %rr   zBad header value: z (bad char: rw   )r   r   rK   rœ   r"   r   ÚlowerÚ	header_reÚsearchÚendswithÚbad_header_value_reÚgroup)r+   ÚitemÚnamer   s       r   r$   r$   ‚  sT  € ÜŒD�‹MœTÑ!â”D˜”Mð	#ô$ð ó CˆÜ”�T“
œeÑ#â”T˜$”Zð!ô	"ô 	”�D“	˜Q‘ÔØ‰ˆˆeÜ   }Ó5ˆÜ! %¨Ó8ˆÜ�—
‘
“ Ñ(ðà"ñ#ô	$ô 	�˜DÐ Ò4 S° _Ø;¸dÑBô	Dä”	× Ñ  Ó&Ð(=ÀÑ(DÔEÜ�D—M‘M #Ó&Ð&ÒA¨t¯}©}¸SÓ/AÐ+AØ1°DÑ8ô	:ä×%Ñ% eÖ,Ü‘AÚÔ)×0Ñ0°Ó7×=Ñ=¸aÕ@ðBö Cñ%Cr   c                 ó  — t        | d«      } t        | j                  d d«      d   «      }d}|D ]:  \  }}t        |d«      }|j                  «       dk(  sŒ&||vr y t	        dd|z  «       Œ< ||vrt	        dd|z  «       y y )	Nr©   r!   r   )éÌ   i0  r±   zcontent-typezJContent-Type header found in a %s response, which must not return content.z,No Content-Type header found in headers (%s))r   r¡   r­   r¶   r   )r*   r+   ÚcodeÚNO_MESSAGE_BODYr½   r   s         r   r%   r%   ›  s¡   € Ü˜v xÓ0€FÜˆv�|‰|˜D !Ó$ QÑ'Ó(€Dð !€OØò B‰ˆˆeÜ   }Ó5ˆØ�:‰:‹<˜>Ó)Ø˜?Ñ*ÙÜ�Að 9Ø<@ñAõ BðBð �?Ñ"Ü�ÐAÀGÑKÕLð #r   c           	      ód   — t        | d u xs t        | «      t        u d| ›dt        | «      ›�«       y )Nz
exc_info (z) is not a tuple: )r   r   rœ   )r,   s    r   r&   r&   «  s-   € ÜˆH˜ÐÒ7¤ X£´%Ð 7øÚ.6¼¸X¼ÐGõIr   c                 óF   — t        t        | t        t        f«       d«       y )NzwYou should not return a string as your application iterator, instead return a single-item list containing a bytestring.)r   Ú
isinstancer   rD   rl   s    r   r5   r5   °  s#   € ô ”
˜8¤c¬5 \Ó2Ð2ð	EõFr   )r	   Ú__all__Úrer}   r™   Úcompiler·   rº   ÚWarningr   r   r   r   r3   r4   r(   rj   r6   r2   r�   rž   r#   r$   r%   r&   r5   r
   r   r   ú<module>rÉ      sÀ   ðñ
iðT ˆ-€ó 
Û 
Û àˆB�J‰JÐ3Ó4€	Ø �b—j‘j Ó0Ð ô�'ô ò
$òHò5÷n7ñ 7÷@8ñ 8÷&ñ ÷4ñ 4÷!?ñ !?òF?#òB"ò#ò#òCò2Mò Ió
Fr   