o
    )Zha                     @   s  d 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	m
Z
mZ ddlmZ ddlmZmZmZmZ dd	lmZmZmZmZmZmZmZmZmZ G d
d dejZG dd deZG dd dej Z!G dd dej Z"eedee eee#df ef eee#df eee#ef f eee#df eee#ef e#f f  Z$G dd deZ%G dd dee%Z&G dd de'Z(G dd de'Z)G dd de)Z*G dd de)Z+G dd de)Z,G d d! d!e)Z-G d"d# d#e(Z.ed$e#d%e/fd&d'Z0ed*d(d'Z0d$ee# d%ee/ fd)d'Z0dS )+ap  Flexible routing implementation.

Tornado routes HTTP requests to appropriate handlers using `Router`
class implementations. The `tornado.web.Application` class is a
`Router` implementation and may be used directly, or the classes in
this module may be used for additional flexibility. The `RuleRouter`
class can match on more criteria than `.Application`, or the `Router`
interface can be subclassed for maximum customization.

`Router` interface extends `~.httputil.HTTPServerConnectionDelegate`
to provide additional routing capabilities. This also means that any
`Router` implementation can be used directly as a ``request_callback``
for `~.httpserver.HTTPServer` constructor.

`Router` subclass must implement a ``find_handler`` method to provide
a suitable `~.httputil.HTTPMessageDelegate` instance to handle the
request:

.. code-block:: python

    class CustomRouter(Router):
        def find_handler(self, request, **kwargs):
            # some routing logic providing a suitable HTTPMessageDelegate instance
            return MessageDelegate(request.connection)

    class MessageDelegate(HTTPMessageDelegate):
        def __init__(self, connection):
            self.connection = connection

        def finish(self):
            self.connection.write_headers(
                ResponseStartLine("HTTP/1.1", 200, "OK"),
                HTTPHeaders({"Content-Length": "2"}),
                b"OK")
            self.connection.finish()

    router = CustomRouter()
    server = HTTPServer(router)

The main responsibility of `Router` implementation is to provide a
mapping from a request to `~.httputil.HTTPMessageDelegate` instance
that will handle this request. In the example above we can see that
routing is possible even without instantiating an `~.web.Application`.

For routing to `~.web.RequestHandler` implementations we need an
`~.web.Application` instance. `~.web.Application.get_handler_delegate`
provides a convenient way to create `~.httputil.HTTPMessageDelegate`
for a given request and `~.web.RequestHandler`.

Here is a simple example of how we can we route to
`~.web.RequestHandler` subclasses by HTTP method:

.. code-block:: python

    resources = {}

    class GetResource(RequestHandler):
        def get(self, path):
            if path not in resources:
                raise HTTPError(404)

            self.finish(resources[path])

    class PostResource(RequestHandler):
        def post(self, path):
            resources[path] = self.request.body

    class HTTPMethodRouter(Router):
        def __init__(self, app):
            self.app = app

        def find_handler(self, request, **kwargs):
            handler = GetResource if request.method == "GET" else PostResource
            return self.app.get_handler_delegate(request, handler, path_args=[request.path])

    router = HTTPMethodRouter(Application())
    server = HTTPServer(router)

`ReversibleRouter` interface adds the ability to distinguish between
the routes and reverse them to the original urls using route's name
and additional arguments. `~.web.Application` is itself an
implementation of `ReversibleRouter` class.

`RuleRouter` and `ReversibleRuleRouter` are implementations of
`Router` and `ReversibleRouter` interfaces and can be used for
creating rule-based routing configurations.

Rules are instances of `Rule` class. They contain a `Matcher`, which
provides the logic for determining whether the rule is a match for a
particular request and a target, which can be one of the following.

1) An instance of `~.httputil.HTTPServerConnectionDelegate`:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/handler"), ConnectionDelegate()),
        # ... more rules
    ])

    class ConnectionDelegate(HTTPServerConnectionDelegate):
        def start_request(self, server_conn, request_conn):
            return MessageDelegate(request_conn)

2) A callable accepting a single argument of `~.httputil.HTTPServerRequest` type:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/callable"), request_callable)
    ])

    def request_callable(request):
        request.write(b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK")
        request.finish()

3) Another `Router` instance:

.. code-block:: python

    router = RuleRouter([
        Rule(PathMatches("/router.*"), CustomRouter())
    ])

Of course a nested `RuleRouter` or a `~.web.Application` is allowed:

.. code-block:: python

    router = RuleRouter([
        Rule(HostMatches("example.com"), RuleRouter([
            Rule(PathMatches("/app1/.*"), Application([(r"/app1/handler", Handler)])),
        ]))
    ])

    server = HTTPServer(router)

In the example below `RuleRouter` is used to route between applications:

.. code-block:: python

    app1 = Application([
        (r"/app1/handler", Handler1),
        # other handlers ...
    ])

    app2 = Application([
        (r"/app2/handler", Handler2),
        # other handlers ...
    ])

    router = RuleRouter([
        Rule(PathMatches("/app1.*"), app1),
        Rule(PathMatches("/app2.*"), app2)
    ])

    server = HTTPServer(router)

For more information on application-level routing see docs for `~.web.Application`.

.. versionadded:: 4.5

    N)partial)httputil)_CallableAdapter)
url_escapeurl_unescapeutf8)app_log)basestring_typeimport_objectre_unescapeunicode_type)	AnyUnionOptional	AwaitableListDictPatternTupleoverloadc                   @   sH   e Zd ZdZdejdedeej fddZ	de
dejdejfd	d
ZdS )RouterzAbstract router interface.requestkwargsreturnc                 K      t  )a  Must be implemented to return an appropriate instance of `~.httputil.HTTPMessageDelegate`
        that can serve the request.
        Routing implementations may pass additional kwargs to extend the routing logic.

        :arg httputil.HTTPServerRequest request: current HTTP request.
        :arg kwargs: additional keyword arguments passed by routing implementation.
        :returns: an instance of `~.httputil.HTTPMessageDelegate` that will be used to
            process the request.
        NotImplementedError)selfr   r    r   F/var/www/html/lang_env/lib/python3.10/site-packages/tornado/routing.pyfind_handler   s   zRouter.find_handlerserver_connrequest_connc                 C   s   t | ||S N)_RoutingDelegate)r   r!   r"   r   r   r   start_request   s   zRouter.start_requestN)__name__
__module____qualname____doc__r   HTTPServerRequestr   r   HTTPMessageDelegater    objectHTTPConnectionr%   r   r   r   r   r      s     
r   c                   @   s*   e Zd ZdZdededee fddZdS )ReversibleRouterzxAbstract router interface for routers that can handle named routes
    and support reversing them to original urls.
    nameargsr   c                 G   r   )a  Returns url string for a given route name and arguments
        or ``None`` if no match is found.

        :arg str name: route name.
        :arg args: url parameters.
        :returns: parametrized url string for a given route name (or ``None``).
        r   )r   r/   r0   r   r   r   reverse_url   s   zReversibleRouter.reverse_urlN)r&   r'   r(   r)   strr   r   r1   r   r   r   r   r.      s    r.   c                   @   s   e Zd ZdededejddfddZdeej	ej
f d	ejdeed  fd
dZdedeed  fddZdddZdddZdS )r$   routerr!   r"   r   Nc                 C   s   || _ || _d | _|| _d S r#   )r!   r"   delegater3   )r   r3   r!   r"   r   r   r   __init__   s   
z_RoutingDelegate.__init__
start_lineheadersc                 C   sj   t |tjsJ tj| j| j||d}| j|| _| jd u r.t	
d|j|j t| j| _| j||S )N)
connectionserver_connectionr6   r7   z$Delegate for %s %s request not found)
isinstancer   RequestStartLiner*   r"   r!   r3   r    r4   r   debugmethodpath_DefaultMessageDelegateheaders_received)r   r6   r7   r   r   r   r   r@      s    
z!_RoutingDelegate.headers_receivedchunkc                 C   s   | j d usJ | j |S r#   )r4   data_received)r   rA   r   r   r   rB     s   z_RoutingDelegate.data_receivedc                 C      | j d usJ | j   d S r#   )r4   finishr   r   r   r   rD   
     z_RoutingDelegate.finishc                 C   rC   r#   )r4   on_connection_closerE   r   r   r   rG     rF   z$_RoutingDelegate.on_connection_closer   N)r&   r'   r(   r   r,   r   r-   r5   r   r;   ResponseStartLineHTTPHeadersr   r   r@   bytesrB   rD   rG   r   r   r   r   r$      s(    



r$   c                   @   s*   e Zd ZdejddfddZdddZdS )	r?   r8   r   Nc                 C   s
   || _ d S r#   )r8   )r   r8   r   r   r   r5     s   
z _DefaultMessageDelegate.__init__c                 C   s*   | j tdddt  | j   d S )NzHTTP/1.1i  z	Not Found)r8   Zwrite_headersr   rI   rJ   rD   rE   r   r   r   rD     s
   z_DefaultMessageDelegate.finishrH   )r&   r'   r(   r   r-   r5   rD   r   r   r   r   r?     s    r?   RuleMatcherc                	   @   s   e Zd ZdZddee ddfddZdeddfddZdddZde	j
dedee	j fddZdede	j
dedee	j fddZdS )
RuleRouterz!Rule-based router implementation.Nrulesr   c                 C   s   g | _ |r| | dS dS )aI  Constructs a router from an ordered list of rules::

            RuleRouter([
                Rule(PathMatches("/handler"), Target),
                # ... more rules
            ])

        You can also omit explicit `Rule` constructor and use tuples of arguments::

            RuleRouter([
                (PathMatches("/handler"), Target),
            ])

        `PathMatches` is a default matcher, so the example above can be simplified::

            RuleRouter([
                ("/handler", Target),
            ])

        In the examples above, ``Target`` can be a nested `Router` instance, an instance of
        `~.httputil.HTTPServerConnectionDelegate` or an old-style callable,
        accepting a request argument.

        :arg rules: a list of `Rule` instances or tuples of `Rule`
            constructor arguments.
        N)rO   	add_rulesr   rO   r   r   r   r5   /  s   zRuleRouter.__init__c                 C   sv   |D ]6}t |ttfr/t|dv sJ t |d tr+tt|d g|dd R  }nt| }| j| 	| qdS )zAppends new rules to the router.

        :arg rules: a list of Rule instances (or tuples of arguments, which are
            passed to Rule constructor).
        )         r      N)
r:   tuplelistlenr	   rL   PathMatchesrO   appendprocess_rule)r   rO   ruler   r   r   rP   N  s   "zRuleRouter.add_rulesr\   rL   c                 C   s   |S )zOverride this method for additional preprocessing of each rule.

        :arg Rule rule: a rule to be processed.
        :returns: the same or modified Rule instance.
        r   r   r\   r   r   r   r[   ^  s   zRuleRouter.process_ruler   r   c                 K   sZ   | j D ]'}|j|}|d ur*|jr|j|d< | j|j|fi |}|d ur*|  S qd S )Ntarget_kwargs)rO   matchermatchr^   get_target_delegatetarget)r   r   r   r\   target_paramsr4   r   r   r   r    f  s   

zRuleRouter.find_handlerrb   rc   c                 K   sx   t |tr|j|fi |S t |tjr#|jdusJ ||j|jS t|r:|jdus.J t	t
|fi ||jS dS )a  Returns an instance of `~.httputil.HTTPMessageDelegate` for a
        Rule's target. This method is called by `~.find_handler` and can be
        extended to provide additional target types.

        :arg target: a Rule's target.
        :arg httputil.HTTPServerRequest request: current request.
        :arg target_params: additional parameters that can be useful
            for `~.httputil.HTTPMessageDelegate` creation.
        N)r:   r   r    r   HTTPServerConnectionDelegater8   r%   r9   callabler   r   )r   rb   r   rc   r   r   r   ra   x  s   
zRuleRouter.get_target_delegater#   r\   rL   r   rL   )r&   r'   r(   r)   r   	_RuleListr5   rP   r[   r   r*   r   r+   r    ra   r   r   r   r   rN   ,  s*    

rN   c                       sX   e Zd ZdZddee ddf fddZd fd	d
Zdede	dee fddZ
  ZS )ReversibleRuleRoutera  A rule-based router that implements ``reverse_url`` method.

    Each rule added to this router may have a ``name`` attribute that can be
    used to reconstruct an original uri. The actual reconstruction takes place
    in a rule's matcher (see `Matcher.reverse`).
    NrO   r   c                    s   i | _ t | d S r#   )named_rulessuperr5   rQ   	__class__r   r   r5     s   zReversibleRuleRouter.__init__r\   rL   c                    s<   t  |}|jr|j| jv rtd|j || j|j< |S )Nz4Multiple handlers named %s; replacing previous value)rj   r[   r/   ri   r   warningr]   rk   r   r   r[     s   z!ReversibleRuleRouter.process_ruler/   r0   c                 G   s\   || j v r| j | jj| S | jD ]}t|jtr+|jj|g|R  }|d ur+|  S qd S r#   )ri   r_   reverserO   r:   rb   r.   r1   )r   r/   r0   r\   Zreversed_urlr   r   r   r1     s   

z ReversibleRuleRouter.reverse_urlr#   rf   )r&   r'   r(   r)   r   rg   r5   r[   r2   r   r1   __classcell__r   r   rk   r   rh     s
    "rh   c                   @   sh   e Zd ZdZ		ddddedeeeef  dee ddf
d	d
Zdedee fddZ	defddZ
dS )rL   zA routing rule.Nr_   rM   rb   r^   r/   r   c                 C   s6   t |tr	t|}|| _|| _|r|ni | _|| _dS )ad  Constructs a Rule instance.

        :arg Matcher matcher: a `Matcher` instance used for determining
            whether the rule should be considered a match for a specific
            request.
        :arg target: a Rule's target (typically a ``RequestHandler`` or
            `~.httputil.HTTPServerConnectionDelegate` subclass or even a nested `Router`,
            depending on routing implementation).
        :arg dict target_kwargs: a dict of parameters that can be useful
            at the moment of target instantiation (for example, ``status_code``
            for a ``RequestHandler`` subclass). They end up in
            ``target_params['target_kwargs']`` of `RuleRouter.get_target_delegate`
            method.
        :arg str name: the name of the rule that can be used to find it
            in `ReversibleRouter.reverse_url` implementation.
        N)r:   r2   r
   r_   rb   r^   r/   )r   r_   rb   r^   r/   r   r   r   r5     s   

zRule.__init__r0   c                 G   s   | j j| S r#   )r_   rn   r   r0   r   r   r   rn     s   zRule.reversec                 C   s   d| j j| j| j| j| jf S Nz%s(%r, %s, kwargs=%r, name=%r))rl   r&   r_   rb   r^   r/   rE   r   r   r   __repr__  s   zRule.__repr__NN)r&   r'   r(   r)   r   r   r   r2   r5   rn   rr   r   r   r   r   rL     s"    
!c                   @   sF   e Zd ZdZdejdeeee	f  fddZ
de	dee fddZd	S )
rM   z*Represents a matcher for request features.r   r   c                 C   r   )a1  Matches current instance against the request.

        :arg httputil.HTTPServerRequest request: current HTTP request
        :returns: a dict of parameters to be passed to the target handler
            (for example, ``handler_kwargs``, ``path_args``, ``path_kwargs``
            can be passed for proper `~.web.RequestHandler` instantiation).
            An empty dict is a valid (and common) return value to indicate a match
            when the argument-passing features are not used.
            ``None`` must be returned to indicate that there is no match.r   r   r   r   r   r   r`     s   
zMatcher.matchr0   c                 G   s   dS )zEReconstructs full url from matcher instance and additional arguments.Nr   rp   r   r   r   rn        zMatcher.reverseN)r&   r'   r(   r)   r   r*   r   r   r2   r   r`   rn   r   r   r   r   rM     s     c                   @   s0   e Zd ZdZdejdeeee	f  fddZ
dS )
AnyMatcheszMatches any request.r   r   c                 C   s   i S r#   r   rt   r   r   r   r`     s   zAnyMatches.matchN)r&   r'   r(   r)   r   r*   r   r   r2   r   r`   r   r   r   r   rv     s    $rv   c                   @   sJ   e Zd ZdZdeeef ddfddZdej	de
eeef  fdd	ZdS )
HostMatchesz@Matches requests from hosts specified by ``host_pattern`` regex.host_patternr   Nc                 C   s6   t |tr|ds|d7 }t|| _d S || _d S )N$)r:   r	   endswithrecompilerx   )r   rx   r   r   r   r5     s
   


zHostMatches.__init__r   c                 C   s   | j |jr	i S d S r#   )rx   r`   Z	host_namert   r   r   r   r`     s   zHostMatches.match)r&   r'   r(   r)   r   r2   r   r5   r   r*   r   r   r   r`   r   r   r   r   rw     s    $rw   c                   @   sF   e Zd ZdZdededdfddZdejde	e
eef  fd	d
ZdS )DefaultHostMatcheszMatches requests from host that is equal to application's default_host.
    Always returns no match if ``X-Real-Ip`` header is present.
    applicationrx   r   Nc                 C   s   || _ || _d S r#   )r~   rx   )r   r~   rx   r   r   r   r5     s   
zDefaultHostMatches.__init__r   c                 C   s"   d|j vr| j| jjri S d S )Nz	X-Real-Ip)r7   rx   r`   r~   Zdefault_hostrt   r   r   r   r`      s   
zDefaultHostMatches.match)r&   r'   r(   r)   r   r   r5   r   r*   r   r   r2   r`   r   r   r   r   r}     s    $r}   c                   @   s~   e Zd ZdZdeeef ddfddZdej	de
eeef  fdd	Zd
ede
e fddZdee
e e
e f fddZdS )rY   z@Matches requests with paths specified by ``path_pattern`` regex.path_patternr   Nc                 C   sl   t |tr|ds|d7 }t|| _n|| _t| jjd| jjfv s,J d| jj	 | 
 \| _| _d S )Nry   r   zDgroups in url regexes must either be all named or all positional: %r)r:   r	   rz   r{   r|   regexrX   
groupindexgroupspattern_find_groups_path_group_count)r   r   r   r   r   r5   +  s   

zPathMatches.__init__r   c                 C   sp   | j |j}|d u rd S | j jsi S g }i }| j jr)tdd |  D }n	dd | D }t||dS )Nc                 s   s$    | ]\}}t |t|fV  qd S r#   )r2   _unquote_or_none).0kvr   r   r   	<genexpr>I  s    
z$PathMatches.match.<locals>.<genexpr>c                 S   s   g | ]}t |qS r   )r   )r   sr   r   r   
<listcomp>M  s    z%PathMatches.match.<locals>.<listcomp>)	path_argspath_kwargs)r   r`   r>   r   r   dict	groupdictitems)r   r   r`   r   r   r   r   r   r`   :  s   

zPathMatches.matchr0   c                 G   s   | j d u rtd| jj t|| jksJ dt|s| j S g }|D ]}t|ttfs0t	|}|
tt|dd q#| j t| S )NzCannot reverse url regex z&required number of arguments not foundF)plus)r   
ValueErrorr   r   rX   r   r:   r   rK   r2   rZ   r   r   rV   )r   r0   Zconverted_argsar   r   r   rn   Q  s   
zPathMatches.reversec              	   C   s   | j j}|dr|dd }|dr|dd }| j j|dkr%dS g }|dD ]F}d|v r[|d}|d	krZzt||d d }W n t	yR   Y  dS w |
d
|  q,zt|}W n t	yl   Y  dS w |
| q,d|| j jfS )zReturns a tuple (reverse string, group count) for a url.

        For example: Given the url pattern /([0-9]{4})/([a-z-]+)/, this method
        would return ('/%s/%s/', 2).
        ^rU   Nry   (rs   )r   z%s )r   r   
startswithrz   r   countsplitindexr   r   rZ   join)r   r   piecesfragmentZ	paren_locZunescaped_fragmentr   r   r   r   `  s4   


zPathMatches._find_groups)r&   r'   r(   r)   r   r2   r   r5   r   r*   r   r   r   r`   rn   r   intr   r   r   r   r   rY   (  s     "rY   c                       sb   e Zd ZdZ		ddeeef dedee	eef  dee ddf
 fdd	Z
defd
dZ  ZS )URLSpeczSpecifies mappings between URLs and handlers.

    .. versionchanged: 4.5
       `URLSpec` is now a subclass of a `Rule` with `PathMatches` matcher and is preserved for
       backwards compatibility.
    Nr   handlerr   r/   r   c                    s4   t |}t |||| |j| _| j| _|| _dS )a  Parameters:

        * ``pattern``: Regular expression to be matched. Any capturing
          groups in the regex will be passed in to the handler's
          get/post/etc methods as arguments (by keyword if named, by
          position if unnamed. Named and unnamed capturing groups
          may not be mixed in the same rule).

        * ``handler``: `~.web.RequestHandler` subclass to be invoked.

        * ``kwargs`` (optional): A dictionary of additional arguments
          to be passed to the handler's constructor.

        * ``name`` (optional): A name for this handler.  Used by
          `~.web.Application.reverse_url`.

        N)rY   rj   r5   r   rb   handler_classr   )r   r   r   r   r/   r_   rk   r   r   r5     s
   
zURLSpec.__init__c                 C   s    d| j j| jj| j| j| jf S rq   )rl   r&   r   r   r   r   r/   rE   r   r   r   rr     s   zURLSpec.__repr__rs   )r&   r'   r(   r)   r   r2   r   r   r   r   r5   rr   ro   r   r   rk   r   r     s     
r   r   r   c                 C      d S r#   r   r   r   r   r   r     ru   r   c                 C   r   r#   r   r   r   r   r   r     ru   c                 C   s   | du r| S t | dddS )zNone-safe wrapper around url_unescape to handle unmatched optional
    groups correctly.

    Note that args are passed as bytes so the handler can decide what
    encoding to use.
    NF)encodingr   )r   r   r   r   r   r     s   )r   Nr   N)1r)   r{   	functoolsr   tornador   Ztornado.httpserverr   Ztornado.escaper   r   r   Ztornado.logr   Ztornado.utilr	   r
   r   r   typingr   r   r   r   r   r   r   r   r   rd   r   r.   r+   r$   r?   r2   rg   rN   rh   r,   rL   rM   rv   rw   r}   rY   r   rK   r   r   r   r   r   <module>   sL    $,.h%1a1