diff --git a/furl/furl.py b/furl/furl.py index cd6d710..183c848 100644 --- a/furl/furl.py +++ b/furl/furl.py @@ -1213,9 +1213,18 @@ def load(self, fragment): elif len(toks) == 1: # Does this fragment look like a path or a query? Default to # path. - if '=' in fragment: # Query example: '#woofs=dogs'. + # + # A '=' alone isn't enough to call it a query: a fragment like + # '#/foo=123' is a path that happens to contain '=' (and its '/' + # would wrongly get percent-encoded if treated as a query key). + # Only treat it as a query when '=' comes before any '/', or no + # '/' is present at all. A '/' before the first '=' signals path + # structure. See issue #172. + if '=' in fragment and ( + '/' not in fragment or fragment.find('=') < fragment.find('/') + ): # Query example: '#woofs=dogs'. self._query.load(fragment) - else: # Path example: '#supinthisthread'. + else: # Path example: '#supinthisthread', '#/foo=123'. self._path.load(fragment) else: # Does toks[1] actually look like a query? Like 'a=a' or diff --git a/tests/test_furl.py b/tests/test_furl.py index bc268c8..d223136 100644 --- a/tests/test_furl.py +++ b/tests/test_furl.py @@ -989,6 +989,16 @@ def test_load(self): {'a': 'a', 'hok sprm': None}), ('/sch/toot?a=a&hok sprm', '/sch/toot', {'a': 'a', 'hok sprm': None}), + # A '=' without a '?' is only a query when '=' precedes any + # '/'. A '/' before the first '=' means the fragment is a + # path that merely contains '=' and its '/' must not be + # percent-encoded as a query key would be (issue #172). + ('/foo=123', '/foo=123', {}), + ('a/b=c', 'a/b=c', {}), + ('/a=1&b=2', '/a=1&b=2', {}), + ('/foo=123/bar=456', '/foo=123/bar=456', {}), + # '=' before any '/' still parses as a query (unchanged). + ('woofs=dogs', '', {'woofs': 'dogs'}), ] for fragment, path, query in comps: