U
    nËjî   ã                   @  sÐ   d dl mZ d dlZd dlZd dlZd dlZd dlZd dlm	Z	 d dl
Z
d dlZ
d dlmZ d dlmZmZ d dlmZ d dlmZmZmZ d dlmZmZmZ ejed	f ZG d
d„ deƒZG dd„ dƒZdS )é    )ÚannotationsN)Ú	parsedate)Úget_route_path)ÚURLÚHeaders)ÚHTTPException)ÚFileResponseÚRedirectResponseÚResponse)ÚReceiveÚScopeÚSendzos.PathLike[str]c                      s&   e Zd ZdZddœ‡ fdd„Z‡  ZS )ÚNotModifiedResponse)zcache-controlzcontent-locationÚdateÚetagÚexpiresÚvaryr   )Úheadersc                   s&   t ƒ jd‡ fdd„| ¡ D ƒd� d S )Ni0  c                   s    i | ]\}}|ˆ j kr||“qS © )ÚNOT_MODIFIED_HEADERS)Ú.0ÚnameÚvalue©Úselfr   ú9/tmp/pip-unpacked-wheel-pzfrzqh9/starlette/staticfiles.pyÚ
<dictcomp>#   s     
  z0NotModifiedResponse.__init__.<locals>.<dictcomp>)Ústatus_coder   )ÚsuperÚ__init__Úitems)r   r   ©Ú	__class__r   r   r       s    þzNotModifiedResponse.__init__)Ú__name__Ú
__module__Ú__qualname__r   r   Ú__classcell__r   r   r!   r   r      s   	r   c                   @  sÄ   e Zd Zddddddœddddddd	œd
d„Zd0ddddœdd„Zdddddœdd„Zdddœdd„Zddddœdd„Zdddœd d!„Zd1d#d$dd%dd&œd'd(„Z	dd)œd*d+„Z
d,d,dd-œd.d/„ZdS )2ÚStaticFilesNFT)Ú	directoryÚpackagesÚhtmlÚ	check_dirÚfollow_symlinkzPathLike | Nonez"list[str | tuple[str, str]] | NoneÚboolÚNone)r(   r)   r*   r+   r,   Úreturnc                C  sX   || _ || _|  ||¡| _|| _d| _|| _|rT|d k	rTtj 	|¡sTt
d|› d�ƒ‚d S )NFúDirectory 'z' does not exist)r(   r)   Úget_directoriesÚall_directoriesr*   Úconfig_checkedr,   ÚosÚpathÚisdirÚRuntimeError)r   r(   r)   r*   r+   r,   r   r   r   r   (   s    	zStaticFiles.__init__zlist[PathLike])r(   r)   r/   c                 C  sÄ   g }|dk	r|  |¡ |pg D ] }t|tƒr6|\}}nd}tj |¡}|dk	s^td|›d�ƒ‚|jdk	sxtd|›d�ƒ‚tj	 
tj	 |jd|¡¡}tj	 |¡s´td|›d|›d�ƒ‚|  |¡ q|S )z�
        Given `directory` and `packages` arguments, return a list of all the
        directories that should be used for serving static files from.
        NZstaticszPackage z could not be found.z..r0   z' in package )ÚappendÚ
isinstanceÚtupleÚ	importlibÚutilÚ	find_specÚAssertionErrorÚoriginr4   r5   ÚnormpathÚjoinr6   )r   r(   r)   ÚdirectoriesÚpackageZstatics_dirÚspecÚpackage_directoryr   r   r   r1   :   s$    	


ÿþzStaticFiles.get_directoriesr   r   r   )ÚscopeÚreceiveÚsendr/   c                 Ã  s\   |d dkst ‚| js*|  ¡ I dH  d| _|  |¡}|  ||¡I dH }||||ƒI dH  dS )z'
        The ASGI entry point.
        ÚtypeÚhttpNT)r>   r3   Úcheck_configÚget_pathÚget_response)r   rF   rG   rH   r5   Úresponser   r   r   Ú__call__W   s    
zStaticFiles.__call__Ústr)rF   r/   c                 C  s"   t |ƒ}tj tjj| d¡Ž ¡S )z�
        Given the ASGI scope, return the `path` string to serve up,
        with OS specific path separators, and any '..', '.' components removed.
        ú/)r   r4   r5   r@   rA   Úsplit)r   rF   Z
route_pathr   r   r   rL   e   s    zStaticFiles.get_pathr
   )r5   rF   r/   c              
   Ã  sž  |d dkrt dd�‚ztj | j|¡I dH \}}W nX tk
rR   t dd�‚Y n< tk
rŒ } z|jtjkrxt dd�‚|‚W 5 d}~X Y nX |r¬t	 
|j¡r¬|  |||¡S |�rLt	 |j¡�rL| j�rLtj |d¡}tj | j|¡I dH \}}|dk	�rLt	 
|j¡�rL|d	  d
¡�s>t|d�}|j|jd
 d�}t|d�S |  |||¡S | j�r�tj | jd¡I dH \}}|�r�t	 
|j¡�r�t||dd�S t dd�‚dS )z`
        Returns an HTTP response, given the incoming path, method and request headers.
        Úmethod)ÚGETÚHEADi•  )r   Ni‘  i”  z
index.htmlr5   rQ   ©rF   )r5   )Úurlz404.html)Ústat_resultr   )r   ÚanyioÚ	to_threadÚrun_syncÚlookup_pathÚPermissionErrorÚOSErrorÚerrnoZENAMETOOLONGÚstatÚS_ISREGÚst_modeÚfile_responseÚS_ISDIRr*   r4   r5   rA   Úendswithr   Úreplacer	   r   )r   r5   rF   Ú	full_pathrX   ÚexcZ
index_pathrW   r   r   r   rM   m   s4    



zStaticFiles.get_responsez!tuple[str, os.stat_result | None])r5   r/   c              
   C  s’   | j D ]†}tj ||¡}| jr,tj |¡}ntj |¡}tj |¡}tj ||g¡|krZqz|t |¡fW   S  t	t
fk
rŠ   Y qY qX qdS )N)Ú N)r2   r4   r5   rA   r,   ÚabspathÚrealpathÚ
commonpathr`   ÚFileNotFoundErrorÚNotADirectoryError)r   r5   r(   Zjoined_pathrg   r   r   r   r\   —   s    
zStaticFiles.lookup_pathéÈ   ÚPathLikezos.stat_resultÚint)rg   rX   rF   r   r/   c                 C  s4   t |d�}t|||d�}|  |j|¡r0t|jƒS |S )NrV   )r   rX   )r   r   Úis_not_modifiedr   r   )r   rg   rX   rF   r   Úrequest_headersrN   r   r   r   rc   ©   s
    

zStaticFiles.file_response)r/   c                 Ã  s€   | j dkrdS ztj tj| j ¡I dH }W n& tk
rP   td| j › d�ƒ‚Y nX t |j	¡s|t 
|j	¡s|td| j › d�ƒ‚dS )zÇ
        Perform a one-off configuration check that StaticFiles is actually
        pointed at a directory, so that we can raise loud errors rather than
        just returning 404 responses.
        NzStaticFiles directory 'z' does not exist.zStaticFiles path 'z' is not a directory.)r(   rY   rZ   r[   r4   r`   rm   r7   rd   rb   ÚS_ISLNK)r   rX   r   r   r   rK   ·   s    
zStaticFiles.check_configr   )Úresponse_headersrs   r/   c                 C  sœ   z2|d }|d }|dd„ |  d¡D ƒkr0W dS W n tk
rF   Y nX z:t|d ƒ}t|d ƒ}|d	k	r€|d	k	r€||kr€W dS W n tk
r–   Y nX d
S )z�
        Given the request and response headers, return `True` if an HTTP
        "Not Modified" response could be returned instead.
        zif-none-matchr   c                 S  s   g | ]}|  d ¡‘qS )z W/)Ústrip)r   Útagr   r   r   Ú
<listcomp>Ï   s     z/StaticFiles.is_not_modified.<locals>.<listcomp>ú,Tzif-modified-sincezlast-modifiedNF)rR   ÚKeyErrorr   )r   ru   rs   Zif_none_matchr   Zif_modified_sinceZlast_modifiedr   r   r   rr   Ç   s    

zStaticFiles.is_not_modified)NN)ro   )r#   r$   r%   r   r1   rO   rL   rM   r\   rc   rK   rr   r   r   r   r   r'   '   s"   ù  ý* ûr'   ) Ú
__future__r   r_   Úimportlib.utilr;   r4   r`   ÚtypingÚemail.utilsr   rY   Zanyio.to_threadZstarlette._utilsr   Zstarlette.datastructuresr   r   Zstarlette.exceptionsr   Zstarlette.responsesr   r	   r
   Zstarlette.typesr   r   r   ÚUnionrP   rp   r   r'   r   r   r   r   Ú<module>   s    