3 \;;�@s�dZdgZddlZddlZddlZejd�Zejd�ZGdd�de�Z dd �Z d d �Z d d�Z Gd d�d�Z Gdd�d�ZGdd�d�ZGdd�d�ZGdd�d�Zdd�Zdd�Zdd�Zdd�Zdd �Zd!d"�Zd#d$�Zd%d&�ZdS)'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 zero or 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@seZdZdZdS)� WSGIWarningz: Raised in response to WSGI-spec-related warnings N)�__name__� __module__� __qualname__�__doc__�rr�(/usr/lib64/python3.6/wsgiref/validate.pyrysrcGs|s t|��dS)N)�AssertionError)Zcond�argsrrr �assert_~sr cCs(t|�tkr|Stdj|t|����dS)Nz!{0} must be of type str (got {1}))�type�strr �format�repr)�value�titlerrr �check_string_type�s rcs�fdd�}|S)a� When applied between a WSGI server and a WSGI application, this middleware will check for WSGI compliancy 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). cs�tt|�dkd�t| d�|\}�t|�g���fdd�}t|d�|d<t|d�|d<�||�}t|dk oz|dkd �t|�t|��S) N�zTwo arguments requiredzNo keyword arguments allowedcs�tt|�dkpt|�dkd|f�t| d�|d}|d}t|�dkrV|d}nd}t|�t|�t||�t|��jd�t�|��S)Nr�zInvalid number of arguments: %szNo keyword arguments allowedr�)r �len� check_status� check_headers�check_content_type�check_exc_info�append� WriteWrapper)r �kw�status�headers�exc_info)�start_response�start_response_startedrr �start_response_wrapper�s      z;validator..lint_app..start_response_wrapperz wsgi.inputz 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$�iterator)� application)r"r#r �lint_app�s  zvalidator..lint_appr)r,r-r)r,r r�s )c@s<eZdZdd�Zdd�Zdd�Zdd�Zd d �Zd d �Zd S)r&cCs ||_dS)N)�input)�self� wsgi_inputrrr �__init__�szInputWrapper.__init__cGs0tt|�dk�|jj|�}tt|�tk�|S)Nr)r rr.�readr �bytes)r/r �vrrr r2�s zInputWrapper.readcGs0tt|�dk�|jj|�}tt|�tk�|S)Nr)r rr.�readliner r3)r/r r4rrr r5�s zInputWrapper.readlinecGsNtt|�dk�|jj|�}tt|�tk�x|D]}tt|�tk�q2W|S)Nr)r rr.� readlinesr �listr3)r/r �lines�linerrr r6�s   zInputWrapper.readlinesccs x|j�}|sdS|VqWdS)N)r5)r/r9rrr �__iter__�s zInputWrapper.__iter__cCstdd�dS)Nrz input.close() must not be called)r )r/rrr �close�szInputWrapper.closeN) rrrr1r2r5r6r:r;rrrr r&�s r&c@s4eZdZdd�Zdd�Zdd�Zdd�Zd d �Zd S) r'cCs ||_dS)N)�errors)r/� wsgi_errorsrrr r1�szErrorWrapper.__init__cCs tt|�tk�|jj|�dS)N)r r rr<�write)r/�srrr r>�szErrorWrapper.writecCs|jj�dS)N)r<�flush)r/rrr r@�szErrorWrapper.flushcCsx|D]}|j|�qWdS)N)r>)r/�seqr9rrr � writelines�s zErrorWrapper.writelinescCstdd�dS)Nrz!errors.close() must not be called)r )r/rrr r;�szErrorWrapper.closeN)rrrr1r>r@rBr;rrrr r'�s r'c@seZdZdd�Zdd�ZdS)rcCs ||_dS)N)�writer)r/Z wsgi_writerrrr r1�szWriteWrapper.__init__cCstt|�tk�|j|�dS)N)r r r3rC)r/r?rrr �__call__�szWriteWrapper.__call__N)rrrr1rDrrrr r�src@seZdZdd�Zdd�ZdS)�PartialIteratorWrappercCs ||_dS)N)r+)r/� wsgi_iteratorrrr r1szPartialIteratorWrapper.__init__cCs t|jd�S)N)r)r+)r/rrr r:szPartialIteratorWrapper.__iter__N)rrrr1r:rrrr rE�srEc@s4eZdZdd�Zdd�Zdd�Zdd�Zd d �Zd S) r)cCs ||_t|�|_d|_||_dS)NF)�original_iterator�iterr+�closed�check_start_response)r/rFrJrrr r1 s zIteratorWrapper.__init__cCs|S)Nr)r/rrr r:szIteratorWrapper.__iter__cCsTt|j d�t|j�}t|�tk r4tdd|f�|jdk rPt|jd�d|_|S)NzIterator read after closedFz$Iterator yielded non-bytestring (%r)zjThe application returns and we started iterating over its body, but start_response has not yet been called)r rI�nextr+r r3rJ)r/r4rrr �__next__s   zIteratorWrapper.__next__cCs d|_t|jd�r|jj�dS)NTr;)rI�hasattrrGr;)r/rrr r;s zIteratorWrapper.closecCs"|jstjjd�t|jd�dS)Nz/Iterator garbage collected without being closed)rI�sys�stderrr>r )r/rrr �__del__#s zIteratorWrapper.__del__N)rrrr1r:rLr;rPrrrr r)s  r)c Cs�tt|�tkdt|�|f�x d,D]}t||kd |f�q$Wx*d-D]"}t||kd||dd�f�qFWd|kr�tjdt�xF|j�D]:}d|kr�q�tt||�tkd|t||�||f�q�Wtt|d�tkd|df�t|dd.kd|d�t |d�t |d�|dd/k�rrBz.wsgi.errors (%r) doesn't have the attribute %s)r@r>rB)r rM)r=rtrrr roqs  rocCsvt|d�}|jdd�d}tt|�dkd|�t|�}t|dkd|�t|�dksb|dd krrtjd |t�dS) N�Statusrrrz)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�splitr rrrrjrkr)rZ status_codeZ status_intrrr rws   rcCstt|�tkd|t|�f�i}x�|D]�}tt|�tkd|t|�f�tt|�dk�|\}}t|d�}t|d�}t|j�dkd|�d||j�<td|ko�d |kd |�ttj|�d |�t|j d � o�|j d � d|�t j|�r(tdd|t j|�j d�f�q(WdS)Nz%Headers (%r) must be of type list: %rz1Individual headers (%r) must be of type tuple: %rrz Header namez Header valuerzyThe 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 '_': %rrz#Bad header value: %r (bad char: %r)) r r r7rmrr�lower� header_re�search�endswith�bad_header_value_re�group)r Z header_names�item�namerrrr r�s0          rcCs~t|d�}t|jdd�d�}d }x@|D]8\}}t|d�}|j�dkr(||krRdStdd|�q(W||krztdd |�dS) Nrurr���0z Header namez 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�)rrrryr~r )rr �codeZNO_MESSAGE_BODYr�rrrr r�s    rcCs*t|dkpt|�tkd|t|�f�dS)Nz exc_info (%r) is not a tuple: %r)r r rm)r!rrr r�srcCstt|ttf� d�dS)NzwYou should not return a string as your application iterator, instead return a single-item list containing a bytestring.)r � isinstancerr3)r+rrr r(�sr()r�__all__�rerNrj�compilerr��Warningrr rrr&r'rrEr)r%rnrorrrrr(rrrr �ns.  7#  #A