� c��j�:��*�dZdgZddlZddlZddlZej d�Zej d�ZGd�de�Z d�Z d �Z d �Z Gd �d �Z Gd �d�ZGd�d�ZGd�d�ZGd�d�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zd�Zy)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��eZdZdZy)� WSGIWarningz: Raised in response to WSGI-spec-related warnings N)�__name__� __module__� __qualname__�__doc__���)/usr/lib64/python3.12/wsgiref/validate.pyrrys��r rc��|st|��y�N)�AssertionError)�cond�argss r �assert_r~s�� ��d�#�#� r c�p�t|�tur|Stdj|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�Hr c����fd�}|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����tt|�dk(d�t| d�|\}�t|�g���fd�}t|d�|d<t |d�|d<�||�}t|duxr|dk7d�t |�t |��S) N�zTwo arguments required�No keyword arguments allowedc�L��tt|�dk(xst|�dk(d|���t| d�|d}|d}t|�dk(r|d}nd}t|�t|�t ||�t |��j d�t�|��S)Nr�zInvalid number of arguments: rr�)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..lint_app..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)rr"� check_environ� InputWrapper� ErrorWrapper�check_iterator�IteratorWrapper)rr)�environr/�iteratorr-r.� applications @@�r �lint_appzvalidator..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 )r9r:s` r rr�s���'A�R �Or c�0�eZdZd�Zd�Zd�Zd�Zd�Zd�Zy)r3c��||_yr)�input)�self� wsgi_inputs r �__init__zInputWrapper.__init__�s ���� r c��tt|�dk(�|jj|�}tt |�t u�|S�Nr!)rr"r=�readr�bytes�r>r�vs r rCzInputWrapper.read�s<����D� �Q��� �D�J�J�O�O�T� "����Q��5� �!��r c��tt|�dk�|jj|�}tt |�t u�|SrB)rr"r=�readlinerrDrEs r rHzInputWrapper.readline�s>����D� �Q��� �D�J�J� � �� &����Q��5� �!��r c���tt|�dk�|jj|�}tt |�t u�|D]}tt |�t u��|SrB)rr"r=� readlinesr�listrD)r>r�lines�lines r rJzInputWrapper.readlines�sY����D� �Q���$�� � �$�$�d�+����U� �t�#�$��D� �D��J�%�'� (��� r c#�`K�|j�x}r|��|j�x}r�yy�wr)rH)r>rMs r �__iter__zInputWrapper.__iter__�s/�����m�m�o�%�d�%��J��m�m�o�%�d�%�s�).�.c��tdd�y)Nrz input.close() must not be called�r�r>s r �closezInputWrapper.close�s ����5�6r N) rrrr@rCrHrJrOrSr r r r3r3�s �� �� � ��7r r3c�*�eZdZd�Zd�Zd�Zd�Zd�Zy)r4c��||_yr)�errors)r>� wsgi_errorss r r@zErrorWrapper.__init__�� ��!�� r c�n�tt|�tu�|jj |�yr)rrrrV�write�r>�ss r rZzErrorWrapper.write�s$����Q��3��� � � ���!�r c�8�|jj�yr)rV�flushrRs r r^zErrorWrapper.flush�s�� � � ���r c�4�|D]}|j|��yr)rZ)r>�seqrMs r � writelineszErrorWrapper.writelines�s���D� �J�J�t� �r c��tdd�y)Nrz!errors.close() must not be calledrQrRs r rSzErrorWrapper.close�s ����6�7r N)rrrr@rZr^rarSr r r r4r4�s��"����8r r4c��eZdZd�Zd�Zy)r(c��||_yr)�writer)r>� wsgi_writers r r@zWriteWrapper.__init__�rXr c�Z�tt|�tu�|j|�yr)rrrDrer[s r �__call__zWriteWrapper.__call__�s����Q��5� �!� � � �A�r N)rrrr@rhr r r r(r(�s ��"�r r(c��eZdZd�Zd�Zy)�PartialIteratorWrapperc��||_yr�r8)r>� wsgi_iterators r r@zPartialIteratorWrapper.__init__�s ��%�� r c�.�t|jd�Sr)r6r8rRs r rOzPartialIteratorWrapper.__iter__s���t�}�}�d�3�3r N)rrrr@rOr r r rjrj�s ��&�4r rjc�*�eZdZd�Zd�Zd�Zd�Zd�Zy)r6c�N�||_t|�|_d|_||_y)NF)�original_iterator�iterr8�closed�check_start_response)r>rmrts r r@zIteratorWrapper.__init__s%��!.����]�+�� ��� �$8��!r c��|Srr rRs r rOzIteratorWrapper.__iter__ s��� r c���t|j d�t|j�}t |�t urtdd|�d��|j �t|j d�d|_|S)NzIterator 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)rrs�nextr8rrDrt)r>rFs r �__next__zIteratorWrapper.__next__si���D�K�K�� (� *� ���� �� ��7�%� � �E�Q�H� I� � $� $� 0� �D�-�-�|� ~�(,�D� %��r c�t�d|_t|jd�r|jj�yy)NTrS)rs�hasattrrqrSrRs r rSzIteratorWrapper.closes0���� � �4�)�)�7� 3� � "� "� (� (� *� 4r c��|jstjjd�t |jd�y)Nz/Iterator garbage collected without being closed)rs�sys�stderrrZrrRs r �__del__zIteratorWrapper.__del__ s0���{�{� �J�J� � �A� C��� � � =� ?r N)rrrr@rOryrSrr r r r6r6s��9� � �+� ?r r6c �b�tt|�tudt|��d|�d��dD]}t||vd|����dD]}t||vd|�d|d d�d ���d |vrtjd t �|j �D]>}d |vr�tt||�tud|�dt||��d||�d���@tt|d�tud|d�d��t|ddvd|dz�t|d�t|d�|ddvr tjd|dzt �t|jd� xs|djd�d|dz�t|jd� xs|djd�d|dz�|jd �r!tt|d �d!k\d"|d z�|jd�std|vd#�t|jd�dk7d$�y)%Nz&Environment is not of the right type: z (environment: rw) �REQUEST_METHOD� SERVER_NAME� SERVER_PORT� wsgi.versionr0r1zwsgi.multithreadzwsgi.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�.zEnvironmental variable z is not a string: z (value: r�z wsgi.version should be a tuple (zwsgi.url_scheme)�http�httpszwsgi.url_scheme unknown: %rr0r1r�)�GET�HEAD�POST�OPTIONS�PATCH�PUT�DELETE�TRACEzUnknown REQUEST_METHOD: %r� SCRIPT_NAME�/z$SCRIPT_NAME doesn't start with /: %r� PATH_INFOz"PATH_INFO doesn't start with /: %r�CONTENT_LENGTHrzInvalid 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 '/')rr�dict�warnings�warnr�keysr�tuple� check_input� check_errors�get� startswith�int)r7�keys r r2r2'sn�� �D��M�T� !� ��=�'� #�$�!�� ��w��69� ;� =� !�<����7�"�"%�s�1�2�w� 0� 1�<� �W�$�� � � 4� �  � �|�|�~�� �#�:� ���W�S�\�"�c�)��D����&��� � 6� 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�dD]}tt||�d|�d|���� y)N)rCrHrJrOz wsgi.input (�) doesn't have the attribute �rr{)r?�attrs r r�r�hs'��=���� �D�)��4� !� "�>r c�J�dD]}tt||�d|�d|���� y)N)r^rZraz wsgi.errors (r�r�)rWr�s r r�r�ns'��0���� �T�*��D� "� #�1r c��t|d�}|jdd�d}tt|�dk(d|z�t |�}t|dk\d|z�t|�dks|dd k7rt j d |zt�yy) N�Statusr!rr z)Status codes must be three characters: %r�dzStatus code is invalid: %r�� zjThe status string (%r) should be a three-digit integer followed by a single space and a status explanation)r�splitrr"r�r�r�r)r*� status_code� status_ints r r#r#ts��� �v�x� 0�F��,�,�t�Q�'��*�K� �C� � �� !�3�k�A�C��[�!�J� �J�#� �;�j�H�I� �6�{�Q��&��)�s�*�� � � B�� �!� #�+r c ���tt|�tud|�dt|����|D�]9}tt|�tud|�dt|����tt |�dk(�|\}}t |d�}t |d�}t|j �dk7d |z�td |vxrd |vd |z�ttj|�d |z�t|jd� xr|jd� d|z�tj|�s��tdd|�dtj|�jd��d����<y)Nz Headers (z) must be of type list: zIndividual 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': %rzBad header name: %r�-�_z#Names may not end in '-' or '_': %rrzBad header value: z (bad char: rw) rrrKr�r"r�lower� header_re�search�endswith�bad_header_value_re�group)r+�item�namers r r$r$�sM�� �D��M�T� !� �D��M� #�$�����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�%r c��t|d�}t|jdd�d�}d}|D]:\}}t|d�}|j�dk(s�&||vryt dd|z��<||vrt dd|z�yy) Nr�r!r)��i0r�z content-typezJContent-Type header found in a %s response, which must not return content.z,No Content-Type header found in headers (%s))rr�r�r�r)r*r+�code�NO_MESSAGE_BODYr�rs r r%r%�s��� �v�x� 0�F� �v�|�|�D�!�$�Q�'� (�D�!�O�� ��e� ��}�5�� �:�:�<�>� )��?�*�� �A�9�<@�A� B� � �?�"���A�G�K�L�#r c �d�t|duxst|�tud|�dt|����y)Nz exc_info (z) is not a tuple: )rrr�)r,s r r&r&�s-�� �H�� � 7��X��%� 7��.6��X��G�Ir c�F�tt|ttf� d�y)NzwYou should not return a string as your application iterator, instead return a single-item list containing a bytestring.)r� isinstancerrDrls r r5r5�s#�� � �8�c�5�\�2� 2� E�Fr )r �__all__�rer}r��compiler�r��Warningrrrrr3r4r(rjr6r2r�r�r#r$r%r&r5r r r �r�s��� i�T �-�� � �� �B�J�J�3� 4� � �b�j�j��0���'�� $�H� 5�n7�7�@8�8�&��4�4�!?�!?�F?#�B"� #� #�C�2M� I� Fr