B
    h`                 @   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e#e/d$d%d&Z0eddd$d'd&Z0ee# ee/ d$d(d&Z0dS ))aq  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               @   s@   e Zd ZdZejeeej dddZ	e
ejejdddZdS )	RouterzAbstract router interface.)requestkwargsreturnc             K   s
   t  dS )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.
        N)NotImplementedError)selfr   r    r   LC:\Users\sanjo\AppData\Local\Qlobot\Launcher\ext_packages\tornado\routing.pyfind_handler   s    zRouter.find_handler)server_connrequest_connr   c             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eeee d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   s
   t  dS )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``).
        N)r   )r   r,   r-   r   r   r   reverse_url   s    zReversibleRouter.reverse_urlN)r#   r$   r%   r&   strr   r   r.   r   r   r   r   r+      s   r+   c               @   s~   e Zd ZeeejddddZeej	ej
f ejeed  dddZeeed  dd	d
ZddddZddddZdS )r!   N)routerr   r    r   c             C   s   || _ || _d | _|| _d S )N)r   r    delegater0   )r   r0   r   r    r   r   r   __init__   s    z_RoutingDelegate.__init__)
start_lineheadersr   c             C   sj   t |tjsttj| j| j||d}| j|| _	| j	d kr\t
d|j|j t| j| _	| j	||S )N)
connectionserver_connectionr3   r4   z$Delegate for %s %s request not found)
isinstancer   RequestStartLineAssertionErrorr'   r    r   r0   r   r1   r   debugmethodpath_DefaultMessageDelegateheaders_received)r   r3   r4   r   r   r   r   r>      s    
z!_RoutingDelegate.headers_received)chunkr   c             C   s   | j d k	st| j |S )N)r1   r9   data_received)r   r?   r   r   r   r@     s    z_RoutingDelegate.data_received)r   c             C   s   | j d k	st| j   d S )N)r1   r9   finish)r   r   r   r   rA   
  s    z_RoutingDelegate.finishc             C   s   | j d k	st| j   d S )N)r1   r9   on_connection_close)r   r   r   r   rB     s    z$_RoutingDelegate.on_connection_close)r#   r$   r%   r   r)   r   r*   r2   r   r8   ResponseStartLineHTTPHeadersr   r   r>   bytesr@   rA   rB   r   r   r   r   r!      s   r!   c               @   s,   e Zd ZejddddZddddZdS )r=   N)r5   r   c             C   s
   || _ d S )N)r5   )r   r5   r   r   r   r2     s    z _DefaultMessageDelegate.__init__)r   c             C   s*   | j tdddt  | j   d S )NzHTTP/1.1i  z	Not Found)r5   write_headersr   rC   rD   rA   )r   r   r   r   rA     s    
z_DefaultMessageDelegate.finish)r#   r$   r%   r   r*   r2   rA   r   r   r   r   r=     s   r=   RuleMatcherc               @   sx   e Zd ZdZdeddddZeddddZddd	d
dZej	e
eej dddZe
ej	e
eej dddZdS )
RuleRouterz!Rule-based router implementation.N)rulesr   c             C   s   g | _ |r| | 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)rJ   	add_rules)r   rJ   r   r   r   r2   /  s    zRuleRouter.__init__c             C   sx   xr|D ]j}t |ttfr^t|dks(tt |d trVtt|d f|dd  }nt| }| j	| 
| qW 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)r7   tuplelistlenr9   r	   rG   PathMatchesrJ   appendprocess_rule)r   rJ   ruler   r   r   rK   N  s    
 zRuleRouter.add_rulesrG   )rV   r   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   rV   r   r   r   rU   ^  s    zRuleRouter.process_rule)r   r   r   c             K   sV   xP| j D ]F}|j|}|d k	r|jr0|j|d< | j|j|f|}|d k	r|S qW d S )Ntarget_kwargs)rJ   matchermatchrW   get_target_delegatetarget)r   r   r   rV   target_paramsr1   r   r   r   r   f  s    
zRuleRouter.find_handler)r[   r   r\   r   c             K   sp   t |tr|j|f|S t |tjrB|jdk	s2t||j|jS t	|rl|jdk	sXtt
t|f||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)r7   r   r   r   HTTPServerConnectionDelegater5   r9   r"   r6   callabler   r   )r   r[   r   r\   r   r   r   rZ   x  s    
zRuleRouter.get_target_delegate)N)r#   r$   r%   r&   	_RuleListr2   rK   rU   r   r'   r   r   r(   r   rZ   r   r   r   r   rI   ,  s   	rI   c                   sT   e Zd ZdZdedd fddZddd fdd	Zeee	e d
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`).
    N)rJ   r   c                s   i | _ tt| | d S )N)named_rulessuperr`   r2   )r   rJ   )	__class__r   r   r2     s    zReversibleRuleRouter.__init__rG   )rV   r   c                s@   t t| |}|jr<|j| jkr0td|j || j|j< |S )Nz4Multiple handlers named %s; replacing previous value)rb   r`   rU   r,   ra   r   warning)r   rV   )rc   r   r   rU     s    
z!ReversibleRuleRouter.process_rule)r,   r-   r   c             G   sZ   || j kr| j | jj| S x8| jD ].}t|jtr$|jj|f| }|d k	r$|S q$W d S )N)ra   rX   reverserJ   r7   r[   r+   r.   )r   r,   r-   rV   reversed_urlr   r   r   r.     s    
z ReversibleRuleRouter.reverse_url)N)r#   r$   r%   r&   r_   r2   rU   r/   r   r   r.   __classcell__r   r   )rc   r   r`     s   r`   c               @   sR   e Zd ZdZddeeeef eddddZeee ddd	Z	ed
ddZ
dS )rG   zA routing rule.NrH   )rX   r[   rW   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)r7   r/   r
   rX   r[   rW   r,   )r   rX   r[   rW   r,   r   r   r   r2     s    
zRule.__init__)r-   r   c             G   s   | j j| S )N)rX   re   )r   r-   r   r   r   re     s    zRule.reverse)r   c             C   s   d| j j| j| j| j| jf S )Nz%s(%r, %s, kwargs=%r, name=%r))rc   r#   rX   r[   rW   r,   )r   r   r   r   __repr__  s    zRule.__repr__)NN)r#   r$   r%   r&   r   r   r/   r2   r   re   rh   r   r   r   r   rG     s    c               @   sB   e Zd ZdZejeeee	f  dddZ
e	ee dddZdS )	rH   z*Represents a matcher for request features.)r   r   c             C   s
   t  dS )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.N)r   )r   r   r   r   r   rY     s    
zMatcher.match)r-   r   c             G   s   dS )zEReconstructs full url from matcher instance and additional arguments.Nr   )r   r-   r   r   r   re     s    zMatcher.reverseN)r#   r$   r%   r&   r   r'   r   r   r/   r   rY   re   r   r   r   r   rH     s   c               @   s.   e Zd ZdZejeeee	f  dddZ
dS )
AnyMatcheszMatches any request.)r   r   c             C   s   i S )Nr   )r   r   r   r   r   rY     s    zAnyMatches.matchN)r#   r$   r%   r&   r   r'   r   r   r/   r   rY   r   r   r   r   ri     s   ri   c               @   sF   e Zd ZdZeeef ddddZej	e
eeef  dddZdS )	HostMatchesz@Matches requests from hosts specified by ``host_pattern`` regex.N)host_patternr   c             C   s4   t |tr*|ds|d7 }t|| _n|| _d S )N$)r7   r	   endswithrecompilerk   )r   rk   r   r   r   r2     s
    

zHostMatches.__init__)r   r   c             C   s   | j |jri S d S )N)rk   rY   	host_name)r   r   r   r   r   rY     s    zHostMatches.match)r#   r$   r%   r&   r   r/   r   r2   r   r'   r   r   r   rY   r   r   r   r   rj     s   rj   c               @   s@   e Zd ZdZeeddddZeje	e
eef  d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.
    N)applicationrk   r   c             C   s   || _ || _d S )N)rr   rk   )r   rr   rk   r   r   r   r2     s    zDefaultHostMatches.__init__)r   r   c             C   s"   d|j kr| j| jjri S d S )Nz	X-Real-Ip)r4   rk   rY   rr   default_host)r   r   r   r   r   rY      s    
zDefaultHostMatches.match)r#   r$   r%   r&   r   r   r2   r   r'   r   r   r/   rY   r   r   r   r   rq     s   rq   c               @   sx   e Zd ZdZeeef ddddZej	e
eeef  dddZee
e d	d
dZee
e e
e f dddZdS )rS   z@Matches requests with paths specified by ``path_pattern`` regex.N)path_patternr   c             C   sl   t |tr*|ds|d7 }t|| _n|| _t| jjd| jjfksXt	d| jj
 |  \| _| _d S )Nrl   r   zDgroups in url regexes must either be all named or all positional: %r)r7   r	   rm   rn   ro   regexrR   
groupindexgroupsr9   pattern_find_groups_path_group_count)r   rt   r   r   r   r2   +  s    

zPathMatches.__init__)r   r   c             C   sp   | j |j}|d krd S | j js&i S g }i }| j jrRtdd |  D }ndd | D }t||dS )Nc             s   s"   | ]\}}t |t|fV  qd S )N)r/   _unquote_or_none).0kvr   r   r   	<genexpr>J  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)ru   rY   r<   rw   rv   dict	groupdictitems)r   r   rY   r   r   r   r   r   rY   :  s    zPathMatches.match)r-   r   c             G   s   | j d krtd| jj t|| jks0tdt|s>| j S g }x8|D ]0}t|tt	fsbt
|}|tt|dd qHW | j t| S )NzCannot reverse url regex z&required number of arguments not foundF)plus)rz   
ValueErrorru   rx   rR   r{   r9   r7   r   rE   r/   rT   r   r   rP   )r   r-   converted_argsar   r   r   re   Q  s    

zPathMatches.reverse)r   c          	   C   s   | j j}|dr|dd }|dr4|dd }| j j|dkrJdS g }xt|dD ]f}d|kr|d}|d	kr|d
||d d   qZyt	|}W n t
k
r   dS X || qZW 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).
        ^rO   Nrl   ()NN)r   z%s )ru   rx   
startswithrm   rw   countsplitindexrT   r   r   join)r   rx   piecesfragmentZ	paren_locZunescaped_fragmentr   r   r   ry   `  s&    


zPathMatches._find_groups)r#   r$   r%   r&   r   r/   r   r2   r   r'   r   r   r   rY   re   r   intry   r   r   r   r   rS   (  s
   rS   c                   sN   e Zd ZdZd	eeef eeeef edd fddZ	ed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.
    N)rx   handlerr   r,   r   c                s8   t |}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)rS   rb   r   r2   ru   r[   handler_classr   )r   rx   r   r   r,   rX   )rc   r   r   r2     s
    zURLSpec.__init__)r   c             C   s    d| j j| jj| j| j| jf S )Nz%s(%r, %s, kwargs=%r, name=%r))rc   r#   ru   rx   r   r   r,   )r   r   r   r   rh     s    zURLSpec.__repr__)NN)r#   r$   r%   r&   r   r/   r   r   r   r2   rh   rg   r   r   )rc   r   r     s
    r   )r   r   c             C   s   d S )Nr   )r   r   r   r   r|     s    r|   c             C   s   d S )Nr   )r   r   r   r   r|     s    c             C   s   | dk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    )1r&   rn   	functoolsr   tornador   tornado.httpserverr   tornado.escaper   r   r   tornado.logr   tornado.utilr	   r
   r   r   typingr   r   r   r   r   r   r   r   r   r]   r   r+   r(   r!   r=   r/   r_   rI   r`   r)   rG   rH   ri   rj   rq   rS   r   rE   r|   r   r   r   r   <module>   sB   ,.&h%1[1