a
    mzfe                     @   s<  d 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 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mZmZ ddlmZ g dZG dd dZdd ZG dd deZeZ G dd deZ!dd Z"dd Z#d!ddZ$G dd dZ%e&d kr8ddl'Z'e'(  dS )"z
Web application
(from web.py)
    N)isclass)BytesIO   )browser
httpserverutils)webapi)wsgi)
debugerror)	iteritems)lstrips)urlparse	urlencodeunquote)reload)applicationauto_applicationsubdir_applicationsubdomain_applicationloadhook
unloadhookautodelegatec                   @   s   e Zd ZdZdi dfddZdd Zdd	 Zd
d Zdd Zdd Z	dd Z
d6ddZdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zg fd*d+Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 ZdS )7r   a  
    Application to delegate requests based on path.

        >>> urls = ("/hello", "hello")
        >>> app = application(urls, globals())
        >>> class hello:
        ...     def GET(self): return "hello"
        >>>
        >>> app.request("/hello").data
        'hello'
     Nc                    s   |d u rt jdd}| |_g _tj t	j
 |rdd   fdd}t||||fdd}tt  rr|  t|   rd	tjv rzt   W n ty   Y n0 d S )
NdebugFc                  S   s2   t jd } t| dd }|o0tjtj|d S )N__main____file__r   )sysmodulesgetattrospathsplitextbasename)modfiler   r   =/var/www/media/lib/python3.9/site-packages/web/application.pymain_module_name@   s
    
z.application.__init__.<locals>.main_module_namec                    s<   |  d|  d }}|du s&|du r*dS |dkr8  }|S )z(find name of the module name from fvars.r   __name__Nr   )get)fvarsr$   name)r&   r   r%   modnameG   s    z%application.__init__.<locals>.modnamec                     s6   t dddg} t|  d}|r2| j_| dS )z%loadhook to reload mapping and fvars.N )
__import__r   __dict__r)   init_mapping)r#   mapping)mapping_namemodule_nameselfr   r%   reload_mappingV   s
    z,application.__init__.<locals>.reload_mappingr   )webconfigr(   r/   r)   
processorsadd_processorr   _loadr   _unloadr   ZdictfindReloaderr   argvr-   ImportError)r3   r0   r)   Z
autoreloadr+   r4   r   )r&   r1   r2   r3   r%   __init__4   s,    
zapplication.__init__c                 C   s   t jj|  d S N)r5   ctx	app_stackappendr3   r   r   r%   r9   n   s    zapplication._loadc                 C   sX   t jjd d t j_t jjrTt jd}|rT|jt j_|jt j_|jt j_|jt j_d S )N_oldctx)r5   r@   rA   r(   homehomepathr    fullpath)r3   Zoldctxr   r   r%   r:   q   s    


zapplication._unloadc                 C   s   t j  d S r?   )r   ZThreadedDictZ	clear_allrC   r   r   r%   _cleanup}   s    zapplication._cleanupc                 C   s   t t|d| _d S )N   )listr   groupr0   )r3   r0   r   r   r%   r/      s    zapplication.init_mappingc                 C   s   | j ||f d S r?   )r0   rB   )r3   pattern	classnamer   r   r%   add_mapping   s    zapplication.add_mappingc                 C   s   | j | dS )a  
        Adds a processor to the application.

            >>> urls = ("/(.*)", "echo")
            >>> app = application(urls, globals())
            >>> class echo:
            ...     def GET(self, name): return name
            ...
            >>>
            >>> def hello(handler): return "hello, " +  handler()
            ...
            >>> app.add_processor(hello)
            >>> app.request("/web.py").data
            'hello, web.py'
        N)r7   rB   )r3   	processorr   r   r%   r8      s    zapplication.add_processor/GET0.0.0.0:8080Fc                    s(  t |}|j}	|j}
|
pd}d|v r.|d }ni }t||||	|t|d}|pPi }| D ] \}}||d| dd < qZd|v r|d|d< d	|v r|d	|d
< |dvr|pd}t	|trt
|}n|}t|d|d< d|vrt||d< t   fdd}|  ||}d| _ S )a  Makes request to this application for the specified path and method.
        Response will be a storage object with data, status and headers.

            >>> urls = ("/hello", "hello")
            >>> app = application(urls, globals())
            >>> class hello:
            ...     def GET(self):
            ...         web.header('Content-Type', 'text/plain')
            ...         return "hello"
            ...
            >>> response = app.request("/hello")
            >>> response.data
            'hello'
            >>> response.status
            '200 OK'
            >>> response.headers['Content-Type']
            'text/plain'

        To use https, use https=True.

            >>> urls = ("/redirect", "redirect")
            >>> app = application(urls, globals())
            >>> class redirect:
            ...     def GET(self): raise web.seeother("/foo")
            ...
            >>> response = app.request("/redirect")
            >>> response.headers['Location']
            'http://0.0.0.0:8080/foo'
            >>> response = app.request("/redirect", https=True)
            >>> response.headers['Location']
            'https://0.0.0.0:8080/foo'

        The headers argument specifies HTTP headers as a mapping object
        such as a dict.

            >>> urls = ('/ua', 'uaprinter')
            >>> class uaprinter:
            ...     def GET(self):
            ...         return 'your user-agent is ' + web.ctx.env['HTTP_USER_AGENT']
            ...
            >>> app = application(urls, globals())
            >>> app.request('/ua', headers = {
            ...      'User-Agent': 'a small jumping bean/1.0 (compatible)'
            ... }).data
            'your user-agent is a small jumping bean/1.0 (compatible)'

        r,   env)	HTTP_HOSTREQUEST_METHOD	PATH_INFOQUERY_STRINGHTTPSZHTTP_-_ZHTTP_CONTENT_LENGTHCONTENT_LENGTHZHTTP_CONTENT_TYPECONTENT_TYPE)HEADrR   utf-8z
wsgi.inputc                    s   |  _ t| _| _d S r?   )statusdictheadersheader_items)r`   rb   responser   r%   start_response  s    
z+application.request.<locals>.start_response    )r   r    queryra   stritemsupperreplacepop
isinstancer   r   encodelenr5   storagewsgifuncjoindata)r3   Z	localpartmethodrt   hostrb   httpskw_pr    Zmaybe_queryrh   rT   kvqrf   r   rd   r%   request   sF    ;


zapplication.requestc                 C   s
   t | S r?   )r   Z
AppBrowserrC   r   r   r%   r   
  s    zapplication.browserc                 C   s&   |  | jtjj\}}| || j|S r?   )_matchr0   r5   r@   r    	_delegater)   )r3   fnargsr   r   r%   handle  s    zapplication.handlec                    s    fdd  j S )Nc              	      s   z< r0 d  dd   } | fddW S   W S W nP tjyR    Y n< ttfyh    Y n&   tt tjd 	 Y n0 d S )Nr   r   c                      s    S r?   r   r   )processr7   r   r%   <lambda>  rg   zEapplication.handle_with_processors.<locals>.process.<locals>.<lambda>)r$   )
r   r5   	HTTPErrorKeyboardInterrupt
SystemExitprint	traceback
format_excr   internalerror)r7   pr   r3   r7   r%   r     s    z3application.handle_with_processors.<locals>.processr   rC   r   r   r%   handle_with_processors  s    z"application.handle_with_processorsc                    s,   dd   fdd}|D ]}||}q|S )z8Returns a WSGI-compatible function for this application.c                 S   s2   zt | }W n ty"   d}Y n0 t|g| S )ziPeeps into an iterator by doing an iteration
            and returns an equivalent iterator.
            r,   )nextStopIteration	itertoolschain)iteratorZ
firstchunkr   r   r%   peep'  s
    
z"application.wsgifunc.<locals>.peepc              
      s      |  zFtjj tjjkr0t  }|rPt|drP |}n|g}W n. tj	y } z|j
g}W Y d }~n
d }~0 0 dd }||}tjjtjj }}||| fdd}t|| S )N__next__c                 s   s0   | D ]&}t |tr|V  qt|dV  qd S )Nr_   )rn   bytesri   ro   )resultrr   r   r%   build_resultG  s    
z8application.wsgifunc.<locals>.wsgi.<locals>.build_resultc                   3   s       dV  d S )Nrg   )rI   r   rC   r   r%   cleanupS  s    z3application.wsgifunc.<locals>.wsgi.<locals>.cleanup)rI   loadr5   r@   ru   rk   nomethodr   hasattrr   rt   r`   rb   r   r   )rT   Z
start_respr   er   r`   rb   r   r   r3   r   r%   r	   5  s"    



z"application.wsgifunc.<locals>.wsgir   )r3   
middlewarer	   mr   r   r%   rr   $  s
    $
zapplication.wsgifuncc                 G   s   t | j| S )a  
        Starts handling requests. If called in a CGI or FastCGI context, it will follow
        that protocol. If called from the command line, it will start an HTTP
        server on the port named in the first command line argument, or, if there
        is no argument, on port 8080.

        `middleware` is a list of WSGI middleware which is applied to the resulting WSGI
        function.
        )r	   Zrunwsgirr   )r3   r   r   r   r%   run^  s    
zapplication.runc                 C   s   t jrt j  dt _dS )z%Stops the http server started by run.N)r   serverstoprC   r   r   r%   r   j  s    
zapplication.stopc                 G   sH   | j | }zddlm} ||W S  tyB   tj | Y S 0 dS )z
        Return a CGI handler. This is mostly useful with Google App Engine.
        There you can just do:

            main = app.cgirun()
        r   run_wsgi_appN)rr    google.appengine.ext.webapp.utilr   r=   wsgirefhandlers
CGIHandlerr   )r3   r   wsgiappr   r   r   r%   cgirunp  s    

zapplication.cgirunc                 G   s   | j | }zftjdd }|d }|d }|dkr:td|dkrH|W S |dkrfddlm} ||W S td	W n" ty   tj	 
| Y S 0 dS )
aI  
        Starts the program in a way that will work with Google app engine,
        no matter which version you are using (2.5 / 2.7)

        If it is 2.5, just normally start it with app.gaerun()

        If it is 2.7, make sure to change the app.yaml handler to point to the
        global variable that contains the result of app.gaerun()

        For example:

        in app.yaml (where code.py is where the main code is located)

            handlers:
            - url: /.*
              script: code.app

        Make sure that the app variable is globally accessible
        NrJ   r   r   z2Google App Engine only supports python 2.5 and 2.7      r   z/Not a supported platform, use python 2.5 or 2.7)rr   r   version_infoEnvironmentErrorr   r   r=   r   r   r   r   )r3   r   r   versionmajorminorr   r   r   r%   gaerun  s&    

zapplication.gaerunc                 C   s  t j}|  d|_g |_d|_| |_|_|d|_	|ddv rR|d |_
n"|dd dv rnd|_
nd	|_
|j
d
 |dd |_tjd|dd|_|j|j |_|j|_|d|_|d|_zt|ddd|_W n  ty   |d|_Y n0 |dddrNt|ddd |j|_t|j|_|drnd|dd |_nd|_|j|j |_t|D ]&\}}t|tr|dd||< qd|_g |_dS )zInitializes ctx using env.z200 OKr,   rU   zwsgi.url_scheme)httprw   rY   )ontrue1rw   r   z://z	[unknown]ZREAL_SCRIPT_NAMEZSCRIPT_NAMEZREMOTE_ADDRrV   rW   latin1utf8SERVER_SOFTWARE)z	lighttpd/znginx/ZREQUEST_URI?r   rX   r_   rl   N) r5   r@   clearr`   rb   outputenvironrT   r(   rv   protocollowerZ
homedomainr   rG   rF   Zrealhomeipru   r   decoder    UnicodeDecodeError
startswithr   splitr   rh   rH   r   rn   rA   )r3   rT   r@   rz   r{   r   r   r%   r     sD    zapplication.loadc           	         s    fdd}|d u rt  nt|tr0| S t|r@||S t|tr|dr|ddd }t j	j
dkrt j	jdd}|r|d	| 7 }t |n<d
|v r|d
d\}}t|d d dg}t||}n|| }||S t|dr| S t  S d S )Nc                    sF   t jj}|dkrt| |sd}t| |s2t | t|  |}|  S )Nr^   rR   )r5   r@   ru   r   r   r   )clsmethZtocallr   r   r%   handle_class  s    

z+application._delegate.<locals>.handle_classz	redirect  r   rR   rX   r,   r   .__call__)r5   notfoundrn   r   r   r   ri   r   r   r@   ru   rT   r(   redirectrsplitr-   r   r   )	r3   fr)   r   r   urlxr#   r   r   r   r%   r     s0    	




zapplication._delegatec                    s   |D ]\ t tr@| r fdd}|d f  S qn:t trdtd f |\}ntd f |}|rdd | D f  S qdS )Nc                      s     S r?   )_delegate_sub_applicationr   patr3   whatr   r%   r     rg   z$application._match.<locals>.<lambda>z^%s\Zc                 S   s   g | ]}|qS r   r   .0r   r   r   r%   
<listcomp>  rg   z&application._match.<locals>.<listcomp>NN)	rn   r   r   ri   r   re_subm
re_compilematchgroups)r3   r0   valuer   r   r   r   r%   r~     s    


zapplication._matchc                 C   sh   t t jt j_t j j|7  _t j j|7  _t jjt|d t j_t jjt|d t j_|	 S )a  Deletes request to sub application `app` rooted at the directory `dir`.
        The home, homepath, path and fullpath values in web.ctx are updated to mimic request
        to the subapp and are restored after it is handled.

        @@Any issues with when used with yield?
        N)
r5   rq   r@   rE   rF   rG   r    rp   rH   r   )r3   dirZappr   r   r%   r     s    z%application._delegate_sub_applicationc                 C   s6   | t jjv r2t jj| }|dkr2t jj|d  S d S )Nr   r   )r5   r@   rA   index)r3   r   r   r   r%   get_parent_app*  s    zapplication.get_parent_appc                 C   s    |   }|r| S t S dS )z.Returns HTTPError with '404 not found' messageN)r   r   r5   Z	_NotFoundr3   parentr   r   r%   r   0  s    zapplication.notfoundc                 C   s2   |   }|r| S tjdr&t S t S dS )z3Returns HTTPError with '500 internal error' messager   N)r   r   r5   r6   r(   r
   Z_InternalErrorr   r   r   r%   r   8  s    zapplication.internalerror)rQ   rR   NrS   NF)r'   
__module____qualname____doc__r>   r9   r:   rI   r/   rO   r8   r}   r   r   r   rr   r   r   r   r   r   r   r~   r   r   r   r   r   r   r   r%   r   %   s<   :      
o:/7$r   c                    s    fdd}|S )Nc                    s4   t |  }|dd  |dd   | j| j|S )Nr.   __weakref__)varscopyrm   r'   	__bases__)r   bodymclsr   r%   	decoratorD  s    z!with_metaclass.<locals>.decoratorr   )r   r   r   r   r%   with_metaclassC  s    r   c                   @   s   e Zd ZdZdd ZdS )r   a  Application similar to `application` but urls are constructed
    automatically using metaclass.

        >>> app = auto_application()
        >>> class hello(app.page):
        ...     def GET(self): return "hello, world"
        ...
        >>> class foo(app.page):
        ...     path = '/foo/.*'
        ...     def GET(self): return "foo"
        >>> app.request("/hello").data
        'hello, world'
        >>> app.request('/foo/bar').data
        'foo'
    c                    s>   t   G  fdddt}t|G dd d}| _d S )Nc                       s   e Zd Z fddZdS )z+auto_application.__init__.<locals>.metapagec                    s8   t | ||| |dd| }|d ur4 ||  d S )Nr    rQ   )typer>   r(   rO   )klassr*   basesattrsr    rC   r   r%   r>   f  s    z4auto_application.__init__.<locals>.metapage.__init__N)r'   r   r   r>   r   rC   r   r%   metapagee  s   r   c                   @   s   e Zd ZdZdS )z'auto_application.__init__.<locals>.pageN)r'   r   r   r    r   r   r   r%   pageo  s   r   )r   r>   r   r   r   )r3   r   r   r   rC   r%   r>   b  s
    

zauto_application.__init__N)r'   r   r   r   r>   r   r   r   r%   r   N  s   r   c                   @   s    e Zd ZdZdd Zdd ZdS )r   aM  
    Application to delegate requests based on the host.

        >>> urls = ("/hello", "hello")
        >>> app = application(urls, globals())
        >>> class hello:
        ...     def GET(self): return "hello"
        >>>
        >>> mapping = (r"hello\.example\.com", app)
        >>> app2 = subdomain_application(mapping)
        >>> app2.request("/hello", host="hello.example.com").data
        'hello'
        >>> response = app2.request("/hello", host="something.example.com")
        >>> response.status
        '404 Not Found'
        >>> response.data
        'not found'
    c                 C   s4   t jjdd }| | j|\}}| || j|S )N:r   )r5   r@   rv   r   r~   r0   r   r)   )r3   rv   r   r   r   r   r%   r     s    zsubdomain_application.handlec                 C   sn   |D ]d\}}t |tr2td| d ||\}}ntd| d |}|r|dd | D f  S qdS )N^$c                 S   s   g | ]}|qS r   r   r   r   r   r%   r     rg   z0subdomain_application._match.<locals>.<listcomp>r   )rn   ri   r   r   r   r   r   )r3   r0   r   r   r   r   r   r   r%   r~     s    
zsubdomain_application._matchN)r'   r   r   r   r   r~   r   r   r   r%   r   z  s   r   c                    s    fdd}|S )z
    Converts a load hook into an application processor.

        >>> app = auto_application()
        >>> def f(): "something done before handling request"
        ...
        >>> app.add_processor(loadhook(f))
    c                    s      |  S r?   r   )handlerhr   r%   rP     s    zloadhook.<locals>.processorr   r   rP   r   r   r%   r     s    
r   c                    s    fdd} fdd|S )z
    Converts an unload hook into an application processor.

        >>> app = auto_application()
        >>> def f(): "something done after handling request"
        ...
        >>> app.add_processor(unloadhook(f))
    c                    sD   z
|  }W n       Y n0 |r6t |dr6|S    |S d S )Nr   )r   )r   r   r   wrapr   r%   rP     s    
zunloadhook.<locals>.processorc                 3   s>    fdd}t   z| V  W q ty6   Y d S 0 qd S )Nc                      s$   z
t W S        Y n0 d S r?   )r   r   )r   r   r   r%   	next_hook  s
    
z+unloadhook.<locals>.wrap.<locals>.next_hook)iterr   )r   r  r   )r   r%   r    s    zunloadhook.<locals>.wrapr   r   r   r   r%   r     s    
r   r,   c                    s    fdd}|S )a0  
    Returns a method that takes one argument and calls the method named prefix+arg,
    calling `notfound()` if there isn't one. Example:

        urls = ('/prefs/(.*)', 'prefs')

        class prefs:
            GET = autodelegate('GET_')
            def GET_password(self): pass
            def GET_privacy(self): pass

    `GET_password` would get called for `/prefs/password` while `GET_privacy` for
    `GET_privacy` gets called for `/prefs/privacy`.

    If a user visits `/prefs/password/change` then `GET_password(self, '/change')`
    is called.
    c                    s|   d|v r,| dd\}} | }d| g}n | }g }t| |rpzt| || W S  tyl   t Y qx0 nt d S )NrQ   r   )r   r   r   	TypeErrorr5   r   )r3   argfirstrestfuncr   prefixr   r%   internal  s    
zautodelegate.<locals>.internalr   )r
  r  r   r	  r%   r     s    r   c                   @   s>   e Zd ZdZejdrdZndZdd Zdd Z	d	d
 Z
dS )r;   z[Checks to see if any loaded modules have changed on disk and,
    if so, reloads them.
    javaz	$py.classz.pycc                 C   s
   i | _ d S r?   )mtimesrC   r   r   r%   r>     s    zReloader.__init__c                 C   s&   t tj }|D ]}| | qd S r?   )rK   r   r   valuescheck)r3   Zsys_modulesr#   r   r   r%   r     s    zReloader.__call__c              	   C   s   |rt |dr|jsd S zt|jj}W n ttfyB   Y d S 0 |j| jj	rtj
|jd d rtt|jd d j|}|| jvr|| j|< n8| j| |k rzt| || j|< W n ty   Y n0 d S )Nr   rD   )r   r   r   statst_mtimeOSErrorIOErrorendswith	__class__SUFFIXr    existsmaxr  r   r=   )r3   r#   mtimer   r   r%   r    s$    
zReloader.checkN)r'   r   r   r   r   platformr   r  r>   r   r  r   r   r   r%   r;     s   r;   r   )r,   ))r   r   r   r   r   Zwsgiref.handlersr   inspectr   ior   r,   r   r   r   r   r5   r	   r
   Z
py3helpersr   r   urllib.parser   r   r   	importlibr   __all__r   r   r   r   r   r   r   r   r;   r'   doctesttestmodr   r   r   r%   <module>   s@       ")(+
',
