})
urls = [
url("/typecheck/(.*)", TypeCheckHandler, name='typecheck'),
- url("/decode_arg/(.*)", DecodeArgHandler),
+ url("/decode_arg/(.*)", DecodeArgHandler, name='decode_arg'),
url("/decode_arg_kw/(?P<arg>.*)", DecodeArgHandler),
url("/linkify", LinkifyHandler),
url("/uimodule_resources", UIModuleResourceHandler),
url("/empty_flush", EmptyFlushCallbackHandler),
url("/header_injection", HeaderInjectionHandler),
]
- return Application(urls,
- template_loader=loader,
- autoescape="xhtml_escape",
- cookie_secret=self.COOKIE_SECRET)
+ self.app = Application(urls,
+ template_loader=loader,
+ autoescape="xhtml_escape",
+ cookie_secret=self.COOKIE_SECRET)
+ return self.app
def fetch_json(self, *args, **kwargs):
response = self.fetch(*args, **kwargs)
u'query': [u'bytes', u'c3a9'],
})
+ def test_reverse_url(self):
+ self.assertEqual(self.app.reverse_url('decode_arg', 'foo'),
+ '/decode_arg/foo')
+ self.assertEqual(self.app.reverse_url('decode_arg', 42),
+ '/decode_arg/42')
+ self.assertEqual(self.app.reverse_url('decode_arg', b('\xe9')),
+ '/decode_arg/%E9')
+ self.assertEqual(self.app.reverse_url('decode_arg', u'\u00e9'),
+ '/decode_arg/%C3%A9')
+
def test_uimodule_unescaped(self):
response = self.fetch("/linkify")
self.assertEqual(response.body,
def reverse_url(self, name, *args):
"""Returns a URL path for handler named `name`
- The handler must be added to the application as a named URLSpec
+ The handler must be added to the application as a named URLSpec.
+
+ Args will be substituted for capturing groups in the URLSpec regex.
+ They will be converted to strings if necessary, encoded as utf8,
+ and url-escaped.
"""
if name in self.named_handlers:
return self.named_handlers[name].reverse(*args)
"not found"
if not len(args):
return self._path
- return self._path % tuple([str(a) for a in args])
+ converted_args = []
+ for a in args:
+ if not isinstance(a, (unicode, bytes_type)):
+ a = str(a)
+ converted_args.append(escape.url_escape(utf8(a)))
+ return self._path % tuple(converted_args)
url = URLSpec