From: Yiliang Tang Date: Sat, 17 Jun 2017 06:09:05 +0000 (+0800) Subject: feat: RedirectHandler to pass GET query X-Git-Tag: v5.0.0~63^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2109%2Fhead;p=thirdparty%2Ftornado.git feat: RedirectHandler to pass GET query --- diff --git a/tornado/httputil.py b/tornado/httputil.py index 5b87ce610..a98273aec 100755 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -942,6 +942,14 @@ def split_host_and_port(netloc): return (host, port) +def qs_to_qsl(qs): + """Generator rewinding a result of ``parse_qs`` back to name-value pairs. + """ + for k, vs in qs.items(): + for v in vs: + yield (k, v) + + _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") _QuotePatt = re.compile(r"[\\].") _nulljoin = ''.join diff --git a/tornado/test/httputil_test.py b/tornado/test/httputil_test.py index d1278567b..7ac799257 100644 --- a/tornado/test/httputil_test.py +++ b/tornado/test/httputil_test.py @@ -3,7 +3,7 @@ from __future__ import absolute_import, division, print_function -from tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp, HTTPServerRequest, parse_request_start_line, parse_cookie +from tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp, HTTPServerRequest, parse_request_start_line, parse_cookie, qs_to_qsl, PY3 from tornado.escape import utf8, native_str from tornado.log import gen_log from tornado.testing import ExpectLog @@ -15,6 +15,11 @@ import logging import pickle import time +if PY3: + import urllib.parse as urllib_parse +else: + import urlparse as urllib_parse + class TestUrlConcat(unittest.TestCase): def test_url_concat_no_query_params(self): @@ -102,6 +107,17 @@ class TestUrlConcat(unittest.TestCase): self.assertEqual(url, "https://localhost/path?y=y") +class QsParseTest(unittest.TestCase): + + def test_parsing(self): + qsstring = "a=1&b=2&a=3" + qs = urllib_parse.parse_qs(qsstring) + qsl = list(qs_to_qsl(qs)) + self.assertIn(('a', '1'), qsl) + self.assertIn(('a', '3'), qsl) + self.assertIn(('b', '2'), qsl) + + class MultipartFormDataTest(unittest.TestCase): def test_file_upload(self): data = b"""\ diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index ffccc02d3..7c33fd901 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -2880,6 +2880,7 @@ class RedirectHandlerTest(WebTestCase): def get_handlers(self): return [ ('/src', WebRedirectHandler, {'url': '/dst'}), + ('/src2', WebRedirectHandler, {'url': '/dst2?foo=bar'}), (r'/(.*?)/(.*?)/(.*)', WebRedirectHandler, {'url': '/{1}/{0}/{2}'})] def test_basic_redirect(self): @@ -2887,6 +2888,16 @@ class RedirectHandlerTest(WebTestCase): self.assertEqual(response.code, 301) self.assertEqual(response.headers['Location'], '/dst') + def test_redirect_with_argument(self): + response = self.fetch('/src?foo=bar', follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers['Location'], '/dst?foo=bar') + + def test_redirect_with_appending_argument(self): + response = self.fetch('/src2?foo2=bar2', follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers['Location'], '/dst2?foo=bar&foo2=bar2') + def test_redirect_pattern(self): response = self.fetch('/a/b/c', follow_redirects=False) self.assertEqual(response.code, 301) diff --git a/tornado/web.py b/tornado/web.py index defd21618..0cc34b8e4 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -2279,7 +2279,11 @@ class RedirectHandler(RequestHandler): self._permanent = permanent def get(self, *args): - self.redirect(self._url.format(*args), permanent=self._permanent) + to_url = self._url.format(*args) + if self.request.query_arguments: + to_url = httputil.url_concat( + to_url, list(httputil.qs_to_qsl(self.request.query_arguments))) + self.redirect(to_url, permanent=self._permanent) class StaticFileHandler(RequestHandler):