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
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
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):
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"""\
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):
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)
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):