From: A. Jesse Jiryu Davis Date: Fri, 28 Oct 2016 03:03:35 +0000 (-0400) Subject: web: Add regex support to RedirectHandler X-Git-Tag: v4.5.0~59^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F1867%2Fhead;p=thirdparty%2Ftornado.git web: Add regex support to RedirectHandler The docs had wrongly claimed this was supported before. Implement it, and update the docs to show the str.format-style syntax we chose. Closes #1861. --- diff --git a/docs/guide/structure.rst b/docs/guide/structure.rst index f0829df0a..715e080f8 100644 --- a/docs/guide/structure.rst +++ b/docs/guide/structure.rst @@ -278,7 +278,7 @@ to the prefix ``/photos/`` instead:: app = tornado.web.Application([ url(r"/photos/(.*)", MyPhotoHandler), url(r"/pictures/(.*)", tornado.web.RedirectHandler, - dict(url=r"/photos/\1")), + dict(url=r"/photos/{0}")), ]) Unlike `.RequestHandler.redirect`, `.RedirectHandler` uses permanent diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 89f340715..b09bb9abf 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -2866,3 +2866,20 @@ class URLSpecReverseTest(unittest.TestCase): def test_reverse_arguments(self): self.assertEqual('/api/v1/foo/bar', url(r'^/api/v1/foo/(\w+)$', None).reverse('bar')) + + +class RedirectHandlerTest(WebTestCase): + def get_handlers(self): + return [ + ('/src', WebRedirectHandler, {'url': '/dst'}), + (r'/(.*?)/(.*?)/(.*)', WebRedirectHandler, {'url': '/{1}/{0}/{2}'})] + + def test_basic_redirect(self): + response = self.fetch('/src', follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers['Location'], '/dst') + + def test_redirect_pattern(self): + response = self.fetch('/a/b/c', follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers['Location'], '/b/a/c') diff --git a/tornado/web.py b/tornado/web.py index a0cb0e8eb..f4c50e3c9 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -2191,13 +2191,29 @@ class RedirectHandler(RequestHandler): application = web.Application([ (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}), ]) + + `RedirectHandler` supports regular expression substitutions. E.g., to + swap the first and second parts of a path while preserving the remainder:: + + application = web.Application([ + (r"/(.*?)/(.*?)/(.*)", web.RedirectHandler, {"url": "/{1}/{0}/{2}"}), + ]) + + The final URL is formatted with `str.format` and the substrings that match + the capturing groups. In the above example, a request to "/a/b/c" would be + formatted like:: + + str.format("/{1}/{0}/{2}", "a", "b", "c") # -> "/b/a/c" + + Use Python's :ref:`format string syntax ` to customize how + values are substituted. """ def initialize(self, url, permanent=True): self._url = url self._permanent = permanent - def get(self): - self.redirect(self._url, permanent=self._permanent) + def get(self, *args): + self.redirect(self._url.format(*args), permanent=self._permanent) class StaticFileHandler(RequestHandler):