Chris McDonough
2012-01-05 92dcb5f1a52d46fec7c043a1b5b4158f3d013c34
- Using a dynamic segment named ``traverse`` in a route pattern like this::

config.add_route('trav_route', 'traversal/{traverse:.*}')

Would cause a ``UnicodeDecodeError`` when the route was matched and the
matched portion of the URL contained any high-order characters. See also
https://github.com/Pylons/pyramid/issues/385 .
3 files modified
74 ■■■■■ changed files
CHANGES.txt 8 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_traversal.py 60 ●●●●● patch | view | raw | blame | history
pyramid/traversal.py 6 ●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -45,6 +45,14 @@
  URLDecodeError if there were any high-order characters in the traversal
  pattern or in the matched dynamic segments.
- Using a dynamic segment named ``traverse`` in a route pattern like this::
    config.add_route('trav_route', 'traversal/{traverse:.*}')
  Would cause a ``UnicodeDecodeError`` when the route was matched and the
  matched portion of the URL contained any high-order characters.  See also
  https://github.com/Pylons/pyramid/issues/385 .
Backwards Incompatibilities
---------------------------
pyramid/tests/test_traversal.py
@@ -1,10 +1,13 @@
import unittest
from pyramid.testing import cleanUp
from pyramid.compat import text_
from pyramid.compat import native_
from pyramid.compat import text_type
from pyramid.compat import url_quote
from pyramid.compat import (
    text_,
    native_,
    text_type,
    url_quote,
    PY3,
    )
class TraversalPathTests(unittest.TestCase):
    def _callFUT(self, path):
@@ -127,6 +130,28 @@
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(result['traversed'], ())
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())
    def test_call_with_pathinfo_highorder(self):
        foo = DummyContext(None, text_(b'Qu\xc3\xa9bec', 'utf-8'))
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        if PY3:
            path_info = b'/Qu\xc3\xa9bec'.encode('latin-1')
        else:
            path_info = b'/Qu\xc3\xa9bec'
        environ = self._getEnviron(PATH_INFO=path_info)
        request = DummyRequest(environ)
        result = policy(request)
        self.assertEqual(result['context'], foo)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'],
            (text_(b'Qu\xc3\xa9bec', 'utf-8'),)
            )
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())
@@ -295,6 +320,33 @@
        self.assertEqual(result['virtual_root'], policy.root)
        self.assertEqual(result['virtual_root_path'], ())
    def test_call_with_vh_root_highorder(self):
        bar = DummyContext(None, 'bar')
        foo = DummyContext(bar, text_(b'Qu\xc3\xa9bec', 'utf-8'))
        root = DummyContext(foo, 'root')
        policy = self._makeOne(root)
        if PY3:
            vhm_root = b'/Qu\xc3\xa9bec'.encode('latin-1')
        else:
            vhm_root = b'/Qu\xc3\xa9bec'
        environ = self._getEnviron(HTTP_X_VHM_ROOT=vhm_root,
                                   PATH_INFO='/bar')
        request = DummyRequest(environ)
        result = policy(request)
        self.assertEqual(result['context'], bar)
        self.assertEqual(result['view_name'], '')
        self.assertEqual(result['subpath'], ())
        self.assertEqual(
            result['traversed'],
            (text_(b'Qu\xc3\xa9bec', 'utf-8'), u'bar')
            )
        self.assertEqual(result['root'], policy.root)
        self.assertEqual(result['virtual_root'], foo)
        self.assertEqual(
            result['virtual_root_path'],
            (text_(b'Qu\xc3\xa9bec', 'utf-8'),)
            )
    def test_non_utf8_path_segment_unicode_path_segments_fails(self):
        from pyramid.exceptions import URLDecodeError
        foo = DummyContext()
pyramid/traversal.py
@@ -667,8 +667,8 @@
        if VH_ROOT_KEY in environ:
            # HTTP_X_VHM_ROOT
            vroot_path = decode_path_info(environ[VH_ROOT_KEY]) 
            vroot_tuple = traversal_path_info(vroot_path)
            vpath = vroot_path + path
            vroot_tuple = split_path_info(vroot_path)
            vpath = vroot_path + path # both will (must) be unicode or asciistr
            vroot_idx = len(vroot_tuple) -1
        else:
            vroot_tuple = ()
@@ -688,7 +688,7 @@
            # and this hurts readability; apologies
            i = 0
            view_selector = self.VIEW_SELECTOR
            vpath_tuple = traversal_path_info(vpath)
            vpath_tuple = split_path_info(vpath)
            for segment in vpath_tuple:
                if segment[:2] == view_selector:
                    return {'context':ob,