]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
allow HTTPServerConnectionDelegate as routing targets 1806/head
authorAndrey Sumin <an.sumin@hh.ru>
Tue, 29 Nov 2016 08:41:02 +0000 (11:41 +0300)
committerAndrey Sumin <an.sumin@hh.ru>
Tue, 29 Nov 2016 08:45:33 +0000 (11:45 +0300)
tornado/httputil.py
tornado/routing.py
tornado/test/routing_test.py

index 8e9361c5c64f1e51a942f166aabc45998c0bec9c..8ea8a01e2dcaf18342a22c096c613436cf52628e 100644 (file)
@@ -337,7 +337,7 @@ class HTTPServerRequest(object):
     """
     def __init__(self, method=None, uri=None, version="HTTP/1.0", headers=None,
                  body=None, host=None, files=None, connection=None,
-                 start_line=None):
+                 start_line=None, server_connection=None):
         if start_line is not None:
             method, uri, version = start_line
         self.method = method
@@ -355,6 +355,7 @@ class HTTPServerRequest(object):
         self.host_name = split_host_and_port(self.host.lower())[0]
         self.files = files or {}
         self.connection = connection
+        self.server_connection = server_connection
         self._start_time = time.time()
         self._finish_time = None
 
index cb584cf3d437ba0947635ee4b3369ba731fcc55f..15baeb489bb21f49d456879d323d51fef5954340 100644 (file)
@@ -60,14 +60,14 @@ routing configurations. For example, `RuleRouter` can be used to route between a
 
     server = HTTPServer(router)
 
-Subclasses of `~.httputil.HTTPMessageDelegate` and old-style callables can also be used as
+Implementations of `~.httputil.HTTPServerConnectionDelegate` and old-style callables can also be used as
 rule targets:
 
 .. code-block:: python
 
     router = RuleRouter([
         Rule(PathMatches("/callable"), request_callable),  # def request_callable(request): ...
-        Rule(PathMatches("/delegate"), HTTPMessageDelegateSubclass)
+        Rule(PathMatches("/delegate"), HTTPServerConnectionDelegateImpl())
     ])
 
     server = HTTPServer(router)
@@ -95,8 +95,8 @@ And of course a nested `RuleRouter` would be a valid thing:
     server = HTTPServer(router)
 
 Rules are instances of `Rule` class. They contain some target (`~.web.Application` instance,
-`~.httputil.HTTPMessageDelegate` subclass, a callable or a nested `Router`) and provide the
-basic routing logic defining whether this rule is a match for a particular request.
+`~.httputil.HTTPServerConnectionDelegate` implementation, a callable or a nested `Router`) and
+provide the basic routing logic defining whether this rule is a match for a particular request.
 This routing logic is implemented in `Matcher` subclasses (see `HostMatches`, `PathMatches`
 and others).
 
@@ -108,7 +108,6 @@ from __future__ import absolute_import, division, print_function, with_statement
 
 import re
 from functools import partial
-from inspect import isclass
 
 from tornado import httputil
 from tornado.httpserver import _CallableAdapter
@@ -139,7 +138,7 @@ class Router(httputil.HTTPServerConnectionDelegate):
         raise NotImplementedError()
 
     def start_request(self, server_conn, request_conn):
-        return _RoutingDelegate(self, request_conn)
+        return _RoutingDelegate(self, server_conn, request_conn)
 
 
 class ReversibleRouter(Router):
@@ -159,15 +158,17 @@ class ReversibleRouter(Router):
 
 
 class _RoutingDelegate(httputil.HTTPMessageDelegate):
-    def __init__(self, router, request_conn):
-        self.connection = request_conn
+    def __init__(self, router, server_conn, request_conn):
+        self.server_conn = server_conn
+        self.request_conn = request_conn
         self.delegate = None
         self.router = router  # type: Router
 
     def headers_received(self, start_line, headers):
         request = httputil.HTTPServerRequest(
-            connection=self.connection, start_line=start_line,
-            headers=headers)
+            connection=self.request_conn,
+            server_connection=self.server_conn,
+            start_line=start_line, headers=headers)
 
         self.delegate = self.router.find_handler(request)
         return self.delegate.headers_received(start_line, headers)
@@ -264,8 +265,8 @@ class RuleRouter(Router):
         if isinstance(target, Router):
             return target.find_handler(request, **target_params)
 
-        elif isclass(target) and issubclass(target, httputil.HTTPMessageDelegate):
-            return target(request.connection)
+        elif isinstance(target, httputil.HTTPServerConnectionDelegate):
+            return target.start_request(request.server_connection, request.connection)
 
         elif callable(target):
             return _CallableAdapter(
@@ -322,7 +323,7 @@ class Rule(object):
             whether the rule should be considered a match for a specific
             request.
         :arg target: a Rule's target (typically a ``RequestHandler`` or
-            `~.httputil.HTTPMessageDelegate` subclass or even a nested `Router`).
+            `~.httputil.HTTPServerConnectionDelegate` subclass or even a nested `Router`).
         :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
index 1d1a858b08468cea5ef38d46dff8d8ad76bd8ce0..37f7cfd3a393ded719694106b96b2d9e619cd342 100644 (file)
@@ -13,7 +13,7 @@
 
 from __future__ import absolute_import, division, print_function, with_statement
 
-from tornado.httputil import HTTPHeaders, HTTPMessageDelegate, ResponseStartLine
+from tornado.httputil import HTTPHeaders, HTTPMessageDelegate, HTTPServerConnectionDelegate, ResponseStartLine
 from tornado.routing import HostMatches, PathMatches, ReversibleRouter, Rule, RuleRouter
 from tornado.testing import AsyncHTTPTestCase
 from tornado.web import Application, RequestHandler
@@ -80,17 +80,22 @@ class CustomRouterTestCase(AsyncHTTPTestCase):
         self.assertEqual(response.body, b"app2: first_handler: /first_handler")
 
 
-class MessageDelegate(HTTPMessageDelegate):
-    def __init__(self, connection):
-        self.connection = connection
+class ConnectionDelegate(HTTPServerConnectionDelegate):
+    def start_request(self, server_conn, request_conn):
 
-    def finish(self):
-        response_body = b"OK"
-        self.connection.write_headers(
-            ResponseStartLine("HTTP/1.1", 200, "OK"),
-            HTTPHeaders({"Content-Length": str(len(response_body))}))
-        self.connection.write(response_body)
-        self.connection.finish()
+        class MessageDelegate(HTTPMessageDelegate):
+            def __init__(self, connection):
+                self.connection = connection
+
+            def finish(self):
+                response_body = b"OK"
+                self.connection.write_headers(
+                    ResponseStartLine("HTTP/1.1", 200, "OK"),
+                    HTTPHeaders({"Content-Length": str(len(response_body))}))
+                self.connection.write(response_body)
+                self.connection.finish()
+
+        return MessageDelegate(request_conn)
 
 
 class RuleRouterTest(AsyncHTTPTestCase):
@@ -107,7 +112,7 @@ class RuleRouterTest(AsyncHTTPTestCase):
             ]),
             Rule(PathMatches("/first_handler"), FirstHandler, name="first_handler"),
             Rule(PathMatches("/request_callable"), request_callable),
-            ("/message_delegate", MessageDelegate)
+            ("/connection_delegate", ConnectionDelegate())
         ])
 
         return app
@@ -118,7 +123,7 @@ class RuleRouterTest(AsyncHTTPTestCase):
         response = self.fetch("/first_handler", headers={'Host': 'www.example.com'})
         self.assertEqual(response.body, b"second_handler: /first_handler")
 
-        response = self.fetch("/message_delegate")
+        response = self.fetch("/connection_delegate")
         self.assertEqual(response.body, b"OK")
 
         response = self.fetch("/request_callable")