U
    †@{iB(  ã                   @  sÂ   d dl mZ d dlZd dl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 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 G dd„ dƒZdd„ ZdS )é    )ÚannotationsN)Únormpath)ÚCallable)ÚHeaders)ÚFileWrapper)Ú
MediaTypes)ÚIsDirectoryError)ÚMissingFileError)ÚRedirect)Ú
StaticFile)Údecode_path_info)Úensure_leading_trailing_slashc                   @  sÎ   e Zd ZdZd/dddddddddœdd	dd
dddddœdd„Zdd„ Zedd„ ƒZd0dd„Zdd„ Z	d1dd„Z
dd„ Zdd„ Zdd „ Zed!d"„ ƒZed2d#d$„ƒZd3d%d&„Zd'd(„ Zd)d*„ Zd+d,„ Zd-d.„ ZdS )4Ú
WhiteNoisei ÌNFé<   Tzutf-8)ÚautorefreshÚmax_ageÚallow_all_originsÚcharsetÚ	mimetypesÚadd_headers_functionÚ
index_fileÚimmutable_file_testÚboolz
int | NoneÚstrzdict[str, str] | Nonez*Callable[[Headers, str, str], None] | Nonezstr | bool | NonezCallable | str | Nonec                  s¬   || _ || _|| _|| _|	| _|
dkr.d| _nt|
tƒr@|
| _nd | _|d k	rvt|ƒspt	 
|¡‰ ‡ fdd„| _n|| _t|d�| _|| _i | _g | _|d k	r¨|  ||¡ d S )NTz
index.htmlc                   s   t ˆ  |¡ƒS ©N)r   Úsearch)ÚpathÚurl©Úregex© ú3/tmp/pip-unpacked-wheel-0d11dmrw/whitenoise/base.pyÚ<lambda>?   ó    z%WhiteNoise.__init__.<locals>.<lambda>)Zextra_types)r   r   r   r   r   r   Ú
isinstancer   ÚcallableÚreÚcompiler   r   Úmedia_typesÚapplicationÚfilesÚdirectoriesÚ	add_files)Úselfr)   ÚrootÚprefixr   r   r   r   r   r   r   r   r    r   r!   Ú__init__   s*    

zWhiteNoise.__init__c                 C  sT   t | dd¡ƒ}| jr"|  |¡}n| j |¡}|d krB|  ||¡S |  |||¡S d S )NZ	PATH_INFOÚ )r   Úgetr   Ú	find_filer*   r)   Úserve)r-   ÚenvironÚstart_responser   Ústatic_filer    r    r!   Ú__call__J   s    zWhiteNoise.__call__c                 C  s\   |   |d |¡}|j› d|jj› �}||t|jƒƒ |jd k	rT| dt¡}||jƒS g S d S )NÚREQUEST_METHODú zwsgi.file_wrapper)Zget_responseÚstatusÚphraseÚlistÚheadersÚfiler2   r   )r7   r5   r6   ÚresponseZstatus_lineZfile_wrapperr    r    r!   r4   U   s    

zWhiteNoise.servec                 C  sv   t j |¡}| t jj¡t jj }t|ƒ}| jrD| j d||f¡ n.t j 	|¡r^|  
||¡ ntjd|› �dd� d S )Nr   zNo directory at: é   )Ú
stacklevel)Úosr   ÚabspathÚrstripÚsepr   r   r+   ÚinsertÚisdirÚupdate_files_dictionaryÚwarningsÚwarn)r-   r.   r/   r    r    r!   r,   `   s    zWhiteNoise.add_filesc                 C  sR   t t|ƒƒ}| ¡ D ]8}|t|ƒd … }| dd¡}|| }| j|||d� qd S )Nú\ú/©Ú
stat_cache)ÚdictÚscantreeÚkeysÚlenÚreplaceÚadd_file_to_dictionary)r-   r.   r/   rO   r   Úrelative_pathÚrelative_urlr   r    r    r!   rI   o   s    z"WhiteNoise.update_files_dictionaryc                 C  s�   | j ||d�rd S | jd k	rr| d| j ¡rr|d t| jƒ … }| d¡}|  ||¡| j|< |  ||¡| j|< |}| j|||d�}|| j|< d S )NrN   rM   )Úis_compressed_variantr   ÚendswithrS   rE   Úredirectr*   Úget_static_file)r-   r   r   rO   Ú	index_urlZindex_no_slashr7   r    r    r!   rU   y   s    
z!WhiteNoise.add_file_to_dictionaryc              	   C  sb   | j d kr| d¡rd S |  |¡s&d S |  |¡D ],}z|  ||¡W   S  tk
rZ   Y q0X q0d S ©NrM   )r   rY   Úurl_is_canonicalÚcandidate_paths_for_urlÚfind_file_at_pathr	   )r-   r   r   r    r    r!   r3   …   s    
zWhiteNoise.find_filec                 c  sR   | j D ]F\}}| |¡rtj ||t|ƒd … ¡}tj ||f¡|kr|V  qd S r   )r+   Ú
startswithrC   r   ÚjoinrS   Úcommonprefix)r-   r   r.   r/   r   r    r    r!   r_   ‘   s
    
z"WhiteNoise.candidate_paths_for_urlc              	   C  sà   |   |¡rt|ƒ‚| jd k	rÔ| d¡rBtj || j¡}|  ||¡S | d| j ¡r|tj |¡rÌ|  	||d t
| jƒ … ¡S nPz|  ||¡W S  tk
rÊ   tj tj || j¡¡rÆ|  	||d ¡ Y S Y nX t|ƒ‚|  ||¡S r]   )rX   r	   r   rY   rC   r   rb   r[   ÚisfilerZ   rS   r   ©r-   r   r   r    r    r!   r`   ˜   s     


zWhiteNoise.find_file_at_pathc                 C  s6   d| krdS t | ƒ}|  d¡r.| dkr.|d7 }|| kS )zƒ
        Check that the URL path is in canonical format i.e. has normalised
        slashes and no path traversal elements
        rL   FrM   )r   rY   )r   Z
normalisedr    r    r!   r^   ­   s    zWhiteNoise.url_is_canonicalc                 C  s<   | dd … dkr8| d d… }|d kr0t j |¡S ||kS dS )Néýÿÿÿ)ú.gzú.brF)rC   r   rd   )r   rO   Zuncompressed_pathr    r    r!   rX   º   s    z WhiteNoise.is_compressed_variantc                 C  sˆ   |d krt j |¡st|ƒ‚tg ƒ}|  |||¡ |  |||¡ | jrNd|d< | jd k	rf|  |||¡ t	|| 
¡ ||d |d dœd�S )NÚ*zAccess-Control-Allow-Originrg   rh   )ÚgzipÚbr)rO   Ú	encodings)rC   r   Úexistsr	   r   Úadd_mime_headersÚadd_cache_headersr   r   r   Úitems)r-   r   r   rO   r>   r    r    r!   r[   Ä   s    
üzWhiteNoise.get_static_filec                 C  sB   | j  |¡}| d¡r&dt| jƒi}ni }|jdt|ƒf|Ž d S )Nztext/r   zContent-Type)r(   Úget_typera   r   r   Ú
add_header)r-   r>   r   r   Ú
media_typeÚparamsr    r    r!   rn   Ö   s
    
zWhiteNoise.add_mime_headersc                 C  s>   |   ||¡rd | j¡|d< n| jd k	r:d| j› d�|d< d S )Nzmax-age={}, public, immutableúCache-Controlúmax-age=ú, public)r   ÚformatÚFOREVERr   )r-   r>   r   r   r    r    r!   ro   Þ   s    ÿ

zWhiteNoise.add_cache_headersc                 C  s   dS )z™
        This should be implemented by sub-classes (see e.g. WhiteNoiseMiddleware)
        or by setting the `immutable_file_test` config option
        Fr    re   r    r    r!   r   æ   s    zWhiteNoise.immutable_file_testc                 C  sv   ||d kr |  d¡d d }n(||| j kr4d}ntd|› d|› �ƒ‚| jdk	rfdd| j› d	�i}ni }t||d
�S )z›
        Return a relative 302 redirect

        We use relative redirects as we don't know the absolute URL the app is
        being hosted under
        rM   éÿÿÿÿz./zCannot handle redirect: z > Nru   rv   rw   )r>   )Úsplitr   Ú
ValueErrorr   r
   )r-   Zfrom_urlZto_urlrW   r>   r    r    r!   rZ   í   s    
zWhiteNoise.redirect)NN)N)N)N)N)Ú__name__Ú
__module__Ú__qualname__ry   r0   r8   Ústaticmethodr4   r,   rI   rU   r3   r_   r`   r^   rX   r[   rn   ro   r   rZ   r    r    r    r!   r      s>     ü	ë 1





	
r   c                 c  s>   t  | ¡D ].}| ¡ r(t|jƒE dH  q
|j| ¡ fV  q
dS )zR
    Recurse the given directory yielding (pathname, os.stat(pathname)) pairs
    N)rC   ÚscandirÚis_dirrQ   r   Ústat)r.   Úentryr    r    r!   rQ     s    rQ   )Ú
__future__r   rC   r&   rJ   Ú	posixpathr   Útypingr   Zwsgiref.headersr   Zwsgiref.utilr   Zwhitenoise.media_typesr   Zwhitenoise.respondersr   r	   r
   r   Zwhitenoise.string_utilsr   r   r   rQ   r    r    r    r!   Ú<module>   s"    n