Ticket #2625: 2625.6.patch

File 2625.6.patch, 6.9 KB (added by magmatt, 3 years ago)
  • twisted/python/test/test_urlpath.py

    diff --git twisted/python/test/test_urlpath.py twisted/python/test/test_urlpath.py
    index 4919cdc..aa86ecb 100644
    class URLPathTestCase(unittest.TestCase): 
    4242        self.assertEqual(str(self.path.here()), 'http://example.com/foo/')
    4343        self.assertEqual(str(self.path.child('').here()), 'http://example.com/foo/bar/')
    4444
     45
     46    def test_child_noQuote(self):
     47        """
     48        C{child} should not quote special characters when quoting is disabled
     49        (default).
     50        """
     51        path = urlpath.URLPath.fromString('http://example.com/foo/bar')
     52        self.assertEquals(str(path.child('" +-\\/')),
     53                          'http://example.com/foo/bar/" +-\\/')
     54
     55
     56    def test_child_quote(self):
     57        """
     58        C{child} should quote special characters when quoting is enabled
     59        """
     60        path = urlpath.URLPath.fromString('http://example.com/foo/bar',
     61                                          quote=True)
     62        self.assertEquals(str(path.child('" +-\\/')),
     63                          'http://example.com/foo/bar/%22%20%2B-%5C%2F')
     64        self.assertEquals(str(path.child('').child('"/')),
     65                          'http://example.com/foo/bar/%22%2F')
     66
     67
     68    def test_sibling_noQuote(self):
     69        """
     70        C{sibling} should not quote special characters when quoting is disabled
     71        (default behavior).
     72        """
     73        path = urlpath.URLPath.fromString('http://example.com/foo/bar')
     74        self.assertEquals(str(path.sibling('"+/')),
     75                          'http://example.com/foo/"+/')
     76
     77
     78    def test_sibling_quote(self):
     79        """
     80        C{sibling} should quote special characters when quoting is enabled.
     81        """
     82        path = urlpath.URLPath.fromString('http://example.com/foo/bar',
     83                                          quote=True)
     84        self.assertEquals(str(path.sibling('"+/')),
     85                          'http://example.com/foo/%22%2B%2F')
     86
     87
     88    def test_click_noQuote(self):
     89        """
     90        The object returned by C{click} should not quote special characters by
     91        default.
     92        """
     93        path = urlpath.URLPath.fromString('http://example.com/foo/bar')
     94        self.assertEquals(str(path.click('foo/bar').child('+/')),
     95                          'http://example.com/foo/foo/bar/+/')
     96
     97
     98    def test_click_quote(self):
     99        """
     100        The object returned by C{click} should inherit the quoting behavior of
     101        the base L{URLPath}
     102        """
     103        path = urlpath.URLPath.fromString('http://example.com/foo/bar',
     104                                          quote=True)
     105        self.assertEquals(str(path.click('foo/bar').child('+/')),
     106                          'http://example.com/foo/foo/bar/%2B%2F')       
     107
     108
  • twisted/python/urlpath.py

    diff --git twisted/python/urlpath.py twisted/python/urlpath.py
    index 1c15f09..a8eeb68 100644
    import urlparse 
    88import urllib
    99
    1010class URLPath:
     11    """
     12    @ivar _quote: See L{__init__}
     13    """
    1114    def __init__(self, scheme='', netloc='localhost', path='',
    12                  query='', fragment=''):
     15                 query='', fragment='', quote=False):
     16        """
     17        @param quote: If C{False} (default) then I won't quote path segments
     18            passed to L{sibling} or L{child} (the caller is responsible for
     19            doing any needed quoting in this case).
     20            If C{True} then I will quote path segments, and the caller
     21            I{should not} quote the path segments.
     22        """
    1323        self.scheme = scheme or 'http'
    1424        self.netloc = netloc
    1525        self.path = path or '/'
    1626        self.query = query
    1727        self.fragment = fragment
     28        self._quote = quote
    1829
    1930    _qpathlist = None
    2031    _uqpathlist = None
     32    _quote = False
    2133   
    2234    def pathList(self, unquote=0, copy=1):
    2335        if self._qpathlist is None:
    class URLPath: 
    3244        else:
    3345            return result
    3446
    35     def fromString(klass, st):
     47    def fromString(klass, st, quote=False):
     48        """
     49        Create a L{URLPath} from a string.
     50
     51        @param st: A I{quoted} url.
     52        @param quote: See L{__init__}
     53        """
    3654        t = urlparse.urlsplit(st)
    37         u = klass(*t)
     55        u = klass(*t, quote=quote)
    3856        return u
    3957
    4058    fromString = classmethod(fromString)
    class URLPath: 
    5270        return URLPath(self.scheme,
    5371                        self.netloc,
    5472                        '/'.join(newpathsegs),
    55                         query)
     73                        query,
     74                        quote=self._quote)
     75
    5676
    57     def sibling(self, path, keepQuery=0):
     77    def _maybeQuoteSegment(self, segment):
     78        """
     79        Return the URL quoted version of C{segment} if quoting is enabled (see
     80        L{__init__.quote<__init__>}) otherwise return C{segment} as-is.
     81        """
     82        if self._quote:
     83            return urllib.quote(segment, '')
     84        else:
     85            return segment
     86
     87
     88    def sibling(self, path, keepQuery=False):
    5889        l = self.pathList()
    59         l[-1] = path
     90        l[-1] = self._maybeQuoteSegment(path)
    6091        return self._pathMod(l, keepQuery)
    6192
    62     def child(self, path, keepQuery=0):
     93
     94    def child(self, path, keepQuery=False):
     95        """
     96        Add a child segment to URL path part.
     97       
     98        @param path: The path segment to add.  The segment should be quoted
     99            (using L{urllib.quote} for instance) unless I have been told to
     100            do the quoting (see L{__init.quote<__init__>}).
     101        @type path: C{str}
     102
     103        @param keepQuery: If set to True, keep the current query part in the
     104            result, otherwise discard it.
     105        @type keepQuery: C{bool}
     106
     107        @return: A new L{URLPath} object with the same values as this one,
     108            but with C{path} added as a new segment to the path.
     109        @rtype: L{URLPath}
     110        """
     111        # Store the quoted version
     112        fixedPath = self._maybeQuoteSegment(path)
    63113        l = self.pathList()
    64114        if l[-1] == '':
    65             l[-1] = path
     115            l[-1] = fixedPath
    66116        else:
    67             l.append(path)
     117            l.append(fixedPath)
    68118        return self._pathMod(l, keepQuery)
    69119
    70     def parent(self, keepQuery=0):
     120
     121    def parent(self, keepQuery=False):
    71122        l = self.pathList()
    72123        if l[-1] == '':
    73124            del l[-2]
    class URLPath: 
    78129            l[-1] = ''
    79130        return self._pathMod(l, keepQuery)
    80131
    81     def here(self, keepQuery=0):
     132    def here(self, keepQuery=False):
    82133        l = self.pathList()
    83134        if l[-1] != '':
    84135            l[-1] = ''
    class URLPath: 
    106157                        netloc,
    107158                        path,
    108159                        query,
    109                         fragment)
     160                        fragment,
     161                        quote=self._quote)
    110162
    111163
    112164