From: afg Date: Mon, 28 Dec 2015 06:06:56 +0000 (+0800) Subject: reverse_url should unescape regex string X-Git-Tag: v4.4.0b1~50^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=207a54a34c0517a6625e3a51a70c82ab04abcc79;p=thirdparty%2Ftornado.git reverse_url should unescape regex string --- diff --git a/tornado/test/util_test.py b/tornado/test/util_test.py index 98378fa05..6a0fa5c4a 100644 --- a/tornado/test/util_test.py +++ b/tornado/test/util_test.py @@ -1,11 +1,12 @@ # coding: utf-8 from __future__ import absolute_import, division, print_function, with_statement +import re import sys import datetime import tornado.escape from tornado.escape import utf8 -from tornado.util import raise_exc_info, Configurable, exec_in, ArgReplacer, timedelta_to_seconds, import_object +from tornado.util import raise_exc_info, Configurable, exec_in, ArgReplacer, timedelta_to_seconds, import_object, re_unescape from tornado.test.util import unittest try: @@ -199,3 +200,16 @@ class ImportObjectTest(unittest.TestCase): # whether the thing being imported is a module or not. # This variant requires a byte string in python 2. self.assertIs(import_object(u'tornado.escape'), tornado.escape) + + +class ReUnescapeTest(unittest.TestCase): + def test_re_unescape(self): + test_strings = ( + '/favicon.ico', + 'index.html', + '\x00\x01\\000', + 'Hello, World!', + '!$@#%;', + ) + for string in test_strings: + self.assertEqual(string, re_unescape(re.escape(string))) diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 9f3582d12..7ae3d8745 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -2763,3 +2763,8 @@ class ApplicationTest(AsyncTestCase): app = Application([]) server = app.listen(0, address='127.0.0.1') server.stop() + + +class URLSpecReverseTest(unittest.TestCase): + def test_reverse(self): + self.assertEqual('/favicon.ico', url(r'/favicon\.ico', None).reverse()) diff --git a/tornado/util.py b/tornado/util.py index 5e083961a..e74be97c7 100644 --- a/tornado/util.py +++ b/tornado/util.py @@ -14,6 +14,7 @@ from __future__ import absolute_import, division, print_function, with_statement import array import os +import re import sys import zlib @@ -172,6 +173,22 @@ def errno_from_exception(e): return None +_re_unescape_split_pattern = re.compile(r'(\\[^0])') +# re.escape('\x00') is a special case + +def re_unescape(s): + ''' + unescape a string escaped by ``re.escape()`` + ''' + parts = [] + for i, splited in enumerate(_re_unescape_split_pattern.split(s)): + if i % 2: + parts.append(splited[1]) + else: + parts.append(splited.replace(r'\000', '\000')) + return ''.join(parts) + + class Configurable(object): """Base class for configurable interfaces. diff --git a/tornado/web.py b/tornado/web.py index c51d5f68a..a5301db16 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -90,7 +90,7 @@ from tornado import stack_context from tornado import template from tornado.escape import utf8, _unicode from tornado.util import (import_object, ObjectDict, raise_exc_info, - unicode_type, _websocket_mask) + unicode_type, _websocket_mask, re_unescape) from tornado.httputil import split_host_and_port @@ -184,7 +184,7 @@ class RequestHandler(object): def initialize(self): """Hook for subclass initialization. Called for each request. - + A dictionary passed as the third argument of a url spec will be supplied as keyword arguments to initialize(). @@ -3024,7 +3024,7 @@ class URLSpec(object): if paren_loc >= 0: pieces.append('%s' + fragment[paren_loc + 1:]) else: - pieces.append(fragment) + pieces.append(re_unescape(fragment)) return (''.join(pieces), self.regex.groups)