return [('/static_url/(.*)', StaticUrlHandler),
('/abs_static_url/(.*)', AbsoluteStaticUrlHandler),
- ('/override_static_url/(.*)', OverrideStaticUrlHandler)]
+ ('/override_static_url/(.*)', OverrideStaticUrlHandler),
+ ('/root_static/(.*)', StaticFileHandler, dict(path='/'))]
def get_app_kwargs(self):
return dict(static_path=relpath('static'))
# is probably a packaging error).
self.assertEqual(response.code, 403)
+ def test_root_static_path(self):
+ # Sometimes people set the StaticFileHandler's path to '/'
+ # to disable Tornado's path validation (in conjunction with
+ # their own validation in get_absolute_path). Make sure
+ # that the stricter validation in 4.2.1 doesn't break them.
+ path = os.path.join(os.path.dirname(__file__), 'static/robots.txt')
+ response = self.get_and_head('/root_static' + path)
+ self.assertEqual(response.code, 200)
+
@wsgi_safe
class StaticDefaultFilenameTest(WebTestCase):
# We must add it back to `root` so that we only match files
# in a directory named `root` instead of files starting with
# that prefix.
- root = os.path.abspath(root) + os.path.sep
+ root = os.path.abspath(root)
+ if not root.endswith(os.path.sep):
+ # abspath always removes a trailing slash, except when
+ # root is '/'. This is an unusual case, but several projects
+ # have independently discovered this technique to disable
+ # Tornado's path validation and (hopefully) do their own,
+ # so we need to support it.
+ root += os.path.sep
# The trailing slash also needs to be temporarily added back
# the requested path so a request to root/ will match.
if not (absolute_path + os.path.sep).startswith(root):