U
    La(                     @   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Zddl	m
Z
 ddl	mZ ddlmZmZmZmZmZmZmZ zd dlmZ W n ek
r   d dlZY nX zd dlmZ W n  ek
r   d dlmZ Y nX zd d	lmZmZ W n& ek
r   d d	lmZmZ Y nX eeZ dZ!dZ"e Z#G d
d de$Z%e#&ddd Z'e#&ddd Z(e#&ddd Z)e#j*dd Z+e#,ddd Z-e#,ddd Z.e/dej0Z1dd Z2dd  Z3d!d" Z4ed#d$Z5d%d& Z6e#7de%d'd(d' Z8e#,d)e#,d*e#,d+e%d,dDd-d.Z9e#7d/e%d,d0d1 Z:e#,d2e%d,d3d4 Z;e#,d5e%d,dEd7d8Z<e#,d9e%d,d:d; Z=e#,d<e%d=d>d? Z>e#,d@e#,dAdBdC Z?dS )F    )
namedtupleN   )__version__)core)static_fileredirectrequestresponse	HTTPErrorBottletemplate)BytesIO)StringIO)urljoinurlparsec                   @   s    e Zd ZdZdd Zdd ZdS )authzPdecorator to apply authentication if specified for the decorated method & actionc                 C   s
   || _ d S Naction)selfr    r   3/tmp/pip-unpacked-wheel-8ds7z0ev/pypiserver/_app.py__init__/   s    zauth.__init__c                    s    fdd}|S )Nc                     sN   j tjkrDtjr tjd d kr0tdddidtjtj sDtd | |S )Nr   i  zWWW-AuthenticatezBasic realm="pypi")headersi  )r   configauthenticatedr   r   r
   Zauther)argskwargsmethodr   r   r   	protector3   s     z auth.__call__.<locals>.protectorr   )r   r   r    r   r   r   __call__2   s    
zauth.__call__N)__name__
__module____qualname____doc__r   r!   r   r   r   r   r   ,   s   r   Zbefore_requestc                   C   s   t tjtj d S r   )loginfor   Zlog_req_frmtr   environr   r   r   r   log_request@   s    r)   c                  C   sB   t tjjd tjj } | jt_| jdd tj	d t_
d S )Nz:///)r   r   urlpartsschemenetlocZcustom_hostpathrstripfullpathlstripcustom_fullpath)parsedr   r   r   print_requestE   s    r4   Zafter_requestc                	   C   s&   t tjttjtjtjtjd d S )N)r	   statusr   bodycookies)	r&   r'   r   Zlog_res_frmtr	   r5   r   r6   _cookiesr   r   r   r   log_responseN   s    r9   c                 C   s   t tjt|  d S r   )r&   r'   r   Zlog_err_frmtvars)
http_errorr   r   r   	log_error\   s    r<   z/favicon.icoc                   C   s   t dS )N  )r
   r   r   r   r   favicona   s    r>   r*   c               	   C   sh   t j} zttt }W n   d}Y nX tjd }t|t j	dd t
|| 	dd | 	dd dS )Nr   
r*   
/packages//simple/)URLVERSIONZNUMPKGSZPACKAGESZSIMPLE)r   r2   lenlistpackagesr   Zwelcome_msgr   urlr/   r   )fpZnumpkgsmsgr   r   r   rootf   s    

rJ   z^[a-z0-9_.!+-]+$c                 C   s   t | dk	S )z7See https://github.com/pypiserver/pypiserver/issues/102N)_bottle_upload_filename_rematch)fnamer   r   r   is_valid_pkg_filename~   s    rN   c                  C   sx   zt jd } W n tk
r,   tddY nX | j }ztt|}|	d W n t
k
rr   tddY nX d S )Ncontent  Missing 'content' file-field!z
index.htmlznot a zip file)r   filesKeyErrorr
   filereadzipfileZipFiler   getinfo	Exception)rO   zip_datazfr   r   r   
doc_upload   s    
r\   c                     s   t jd t jd r s6d} td|  f tt fddtt }t	|dkrttdd	 f |D ]}t
|j qxd S )
Nnameversionz4Missing 'name'/'version' fields: name=%s, version=%srP   c                    s   | j  ko| jkS r   )pkgnamer^   )pkgr]   r^   r   r   <lambda>       zremove_pkg.<locals>.<lambda>r   r=   z%s (%s) not found)r   formsgetr
   rE   filterr   find_packagesrF   rD   osunlinkfn)rI   pkgsr`   r   ra   r   
remove_pkg   s    
rl   Uploadzpkg sigc                  C   s   t dd dD } | js$tdd| jrTd| jj | jjkrTtdd| j| jf | D ]}|sbqXt|jr|t|jd krtdd|j t	j
sttj|jrtd	|j td
d|j ttj|j|j tjrtjd }nd}td||j qXd S )Nc                 s   s   | ]}t j|d V  qd S r   )r   rR   re   .0fr   r   r   	<genexpr>   s    zfile_upload.<locals>.<genexpr>)rO   Zgpg_signaturerP   rQ   z%s.ascz&Unrelated signature %r for package %r!zBad filename: %sz]Cannot upload %r since it already exists! 
  You may start server with `--overwrite` option. i  zLPackage %r already exists!
  You may start server with `--overwrite` option.r   ZanonzUser %r stored %r.)rm   _maker`   r
   sigZraw_filenamerN   r   Zguess_pkgname_and_versionr   	overwriteexistsrF   rJ   r&   warnstoresaver   r   r'   )ZufilesZufuserr   r   r   file_upload   sJ    

rz   updatec                  C   s   zt jd } W n tk
r,   tddY nX | dkrDtd|  n>| dkrTt  n.| dkrdt  n| dkrtt  ntdd	|  d
S )Nz:actionrP   zMissing ':action' field!)verifyZsubmitzIgnored ':action': %sr\   rl   rz   zUnsupported ':action' field: %s )	r   rd   rS   r
   r&   warningr\   rl   rz   r   r   r   r   r{      s    z/simplez/simple/:prefixz	/packagesrE   c                 C   s   t tjd dS )Nr*   -  )r   r   r2   prefixr   r   r   pep_503_redirects   s    r   z/RPC2c                  C   s   t jjtj} | dd jd j	 }t
d| |dkr| dd jd j	 }g }d}t D ]:}|j|dkr||j|j|jd}|| |d7 }qftj|fddd	}|S d
S )z%Handle pip-style RPC2 search requests
methodNamer   z Processing RPC2 request for '%s'searchstring)Z_pypi_orderingr^   r]   summaryr   T)methodresponseN)xmldomminidomparser   r6   ZgetElementsByTagName
childNodesZ	wholeTextstripr&   r'   rF   r_   countr^   append	xmlrpclibdumps)parser
methodnamevaluer	   ZorderingpdZcall_stringr   r   r   
handle_rpc   s8    


  r   rA   c                  C   s    t tt } d}t|| dS )Na      <html>
        <head>
            <title>Simple Index</title>
        </head>
        <body>
            <h1>Simple Index</h1>
            % for p in links:
                 <a href="{{p}}/">{{p}}</a><br>
            % end
        </body>
    </html>
    links)sortedr   Zget_prefixesrF   r   )r   tmplr   r   r   simpleindex  s    r   z/simple/:prefix/r}   c                    s   t | }| |kr"td|dS tt jt | ddd d}|sntjr`tdtj	
d| f S td	d
| S tj  fdd|D }d}t|| |dS )Nz/simple/{0}/r   r   c                 S   s   | j | jfS r   )parsed_versionrelfnxr   r   r   rb   3  rc   zsimple.<locals>.<lambda>keyz%s/%s/r*   r=   Not Found (%s does not exist)

c              	      s0   g | ](}t j|jt d |tj fqS )z../../packages/%s)rh   r.   basenamer   r   fname_and_hashr   	hash_algorn   rH   r   r   
<listcomp>=  s    zsimple.<locals>.<listcomp>a!      <html>
        <head>
            <title>Links for {{prefix}}</title>
        </head>
        <body>
            <h1>Links for {{prefix}}</h1>
            % for file, href in links:
                 <a href="{{href}}">{{file}}</a><br>
            % end
        </body>
    </html>
    )r   r   )r   Znormalize_pkgname_for_urlr   formatr   rg   rF   r   Zredirect_to_fallbackZfallback_urlr/   r
   r   r2   r   )r   
normalizedrR   r   r   r   r   r   simple)  s&    

	r   r@   c                     s@   t j ttt dd d}  fdd| D }d}t||dS )Nc                 S   s   t j| j| j| jfS r   )rh   r.   dirnamer   r_   r   r   r   r   r   rb   \  rc   zlist_packages.<locals>.<lambda>r   c                    s$   g | ]}|j t |tjfqS r   )
relfn_unixr   r   r   r   rn   r   r   r   r   ^  s   z!list_packages.<locals>.<listcomp>a      <html>
        <head>
            <title>Index of packages</title>
        </head>
        <body>
            <h1>Index of packages</h1>
            % for file, href in links:
                 <a href="{{href}}">{{file}}</a><br>
            % end
        </body>
    </html>
    r   )r   r2   r   r   rg   rF   r   )rR   r   r   r   r   r   list_packagesV  s    

r   z/packages/:filename#.*#downloadc                 C   sl   t t }|D ]L}|j}|| krt| |jt| d d}tj	rT|
ddtj	  |  S qtdd|  S )Nr   )rJ   mimetypezCache-Controlzpublic, max-age=%sr=   r   )r   rg   rF   r   r   rJ   	mimetypes
guess_typer   Zcache_controlZ
set_headerr
   )filenameentriesr   rp   r	   r   r   r   server_staticr  s      
r   z/:prefixz	/:prefix/c                 C   s   t tt| S )z'Redirect unknown root URLs to /simple/.)r   r   Zget_bad_url_redirect_pathr   r   r   r   r   bad_url  s    r   )N)r}   )@collectionsr   loggingr   rh   rerV   Zxml.dom.minidomr   r}   r   r   Zbottler   r   r   r	   r
   r   r   xmlrpc.clientclientr   ImportErrorior   r   urllib.parser   r   	getLoggerr"   r&   rF   r   Zappobjectr   hookr)   r4   r9   errorr<   Zrouter>   rJ   compileIrK   rN   r\   rl   rm   rz   postr{   r   r   r   r   r   r   r   r   r   r   r   <module>   s   $








-#+