123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- # Licensed under the Apache License, Version 2.0 (the "License"); you may
- # not use this file except in compliance with the License. You may obtain
- # a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- # License for the specific language governing permissions and limitations
- # under the License.
- from __future__ import absolute_import, division, print_function
- from tornado.httputil import HTTPHeaders, HTTPMessageDelegate, HTTPServerConnectionDelegate, ResponseStartLine # noqa: E501
- from tornado.routing import HostMatches, PathMatches, ReversibleRouter, Router, Rule, RuleRouter
- from tornado.testing import AsyncHTTPTestCase
- from tornado.web import Application, HTTPError, RequestHandler
- from tornado.wsgi import WSGIContainer
- class BasicRouter(Router):
- def find_handler(self, request, **kwargs):
- 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()
- return MessageDelegate(request.connection)
- class BasicRouterTestCase(AsyncHTTPTestCase):
- def get_app(self):
- return BasicRouter()
- def test_basic_router(self):
- response = self.fetch("/any_request")
- self.assertEqual(response.body, b"OK")
- 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])
- class HTTPMethodRouterTestCase(AsyncHTTPTestCase):
- def get_app(self):
- return HTTPMethodRouter(Application())
- def test_http_method_router(self):
- response = self.fetch("/post_resource", method="POST", body="data")
- self.assertEqual(response.code, 200)
- response = self.fetch("/get_resource")
- self.assertEqual(response.code, 404)
- response = self.fetch("/post_resource")
- self.assertEqual(response.code, 200)
- self.assertEqual(response.body, b"data")
- def _get_named_handler(handler_name):
- class Handler(RequestHandler):
- def get(self, *args, **kwargs):
- if self.application.settings.get("app_name") is not None:
- self.write(self.application.settings["app_name"] + ": ")
- self.finish(handler_name + ": " + self.reverse_url(handler_name))
- return Handler
- FirstHandler = _get_named_handler("first_handler")
- SecondHandler = _get_named_handler("second_handler")
- class CustomRouter(ReversibleRouter):
- def __init__(self):
- super(CustomRouter, self).__init__()
- self.routes = {}
- def add_routes(self, routes):
- self.routes.update(routes)
- def find_handler(self, request, **kwargs):
- if request.path in self.routes:
- app, handler = self.routes[request.path]
- return app.get_handler_delegate(request, handler)
- def reverse_url(self, name, *args):
- handler_path = '/' + name
- return handler_path if handler_path in self.routes else None
- class CustomRouterTestCase(AsyncHTTPTestCase):
- def get_app(self):
- class CustomApplication(Application):
- def reverse_url(self, name, *args):
- return router.reverse_url(name, *args)
- router = CustomRouter()
- app1 = CustomApplication(app_name="app1")
- app2 = CustomApplication(app_name="app2")
- router.add_routes({
- "/first_handler": (app1, FirstHandler),
- "/second_handler": (app2, SecondHandler),
- "/first_handler_second_app": (app2, FirstHandler),
- })
- return router
- def test_custom_router(self):
- response = self.fetch("/first_handler")
- self.assertEqual(response.body, b"app1: first_handler: /first_handler")
- response = self.fetch("/second_handler")
- self.assertEqual(response.body, b"app2: second_handler: /second_handler")
- response = self.fetch("/first_handler_second_app")
- self.assertEqual(response.body, b"app2: first_handler: /first_handler")
- class ConnectionDelegate(HTTPServerConnectionDelegate):
- def start_request(self, server_conn, request_conn):
- 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):
- def get_app(self):
- app = Application()
- def request_callable(request):
- request.connection.write_headers(
- ResponseStartLine("HTTP/1.1", 200, "OK"),
- HTTPHeaders({"Content-Length": "2"}))
- request.connection.write(b"OK")
- request.connection.finish()
- router = CustomRouter()
- router.add_routes({
- "/nested_handler": (app, _get_named_handler("nested_handler"))
- })
- app.add_handlers(".*", [
- (HostMatches("www.example.com"), [
- (PathMatches("/first_handler"),
- "tornado.test.routing_test.SecondHandler", {}, "second_handler")
- ]),
- Rule(PathMatches("/.*handler"), router),
- Rule(PathMatches("/first_handler"), FirstHandler, name="first_handler"),
- Rule(PathMatches("/request_callable"), request_callable),
- ("/connection_delegate", ConnectionDelegate())
- ])
- return app
- def test_rule_based_router(self):
- response = self.fetch("/first_handler")
- self.assertEqual(response.body, b"first_handler: /first_handler")
- response = self.fetch("/first_handler", headers={'Host': 'www.example.com'})
- self.assertEqual(response.body, b"second_handler: /first_handler")
- response = self.fetch("/nested_handler")
- self.assertEqual(response.body, b"nested_handler: /nested_handler")
- response = self.fetch("/nested_not_found_handler")
- self.assertEqual(response.code, 404)
- response = self.fetch("/connection_delegate")
- self.assertEqual(response.body, b"OK")
- response = self.fetch("/request_callable")
- self.assertEqual(response.body, b"OK")
- response = self.fetch("/404")
- self.assertEqual(response.code, 404)
- class WSGIContainerTestCase(AsyncHTTPTestCase):
- def get_app(self):
- wsgi_app = WSGIContainer(self.wsgi_app)
- class Handler(RequestHandler):
- def get(self, *args, **kwargs):
- self.finish(self.reverse_url("tornado"))
- return RuleRouter([
- (PathMatches("/tornado.*"), Application([(r"/tornado/test", Handler, {}, "tornado")])),
- (PathMatches("/wsgi"), wsgi_app),
- ])
- def wsgi_app(self, environ, start_response):
- start_response("200 OK", [])
- return [b"WSGI"]
- def test_wsgi_container(self):
- response = self.fetch("/tornado/test")
- self.assertEqual(response.body, b"/tornado/test")
- response = self.fetch("/wsgi")
- self.assertEqual(response.body, b"WSGI")
- def test_delegate_not_found(self):
- response = self.fetch("/404")
- self.assertEqual(response.code, 404)
|