From 33b7c4bdd0f5a9a97a0e2dcdfbf8a24ae859de1a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 15 Feb 2018 17:51:50 +0100 Subject: [PATCH] urlmatch: Fix and test port handling --- qutebrowser/utils/urlmatch.py | 18 +++++++----- tests/unit/utils/test_urlmatch.py | 46 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/qutebrowser/utils/urlmatch.py b/qutebrowser/utils/urlmatch.py index 2291fe9e3..390ba733f 100644 --- a/qutebrowser/utils/urlmatch.py +++ b/qutebrowser/utils/urlmatch.py @@ -42,6 +42,9 @@ class UrlPattern: """A Chromium-like URL matching pattern. + Class attributes: + DEFAULT_PORTS: The default ports used for schemes which support ports. + Attributes: _pattern: The given pattern as string. _match_all: Whether the pattern should match all URLs. @@ -56,6 +59,8 @@ class UrlPattern: _port: The port to match to as integer, or None for any port. """ + DEFAULT_PORTS = {'https': 443, 'http': 80, 'ftp': 21} + def __init__(self, pattern): # Make sure all attributes are initialized if we exit early. self._pattern = pattern @@ -169,11 +174,8 @@ class UrlPattern: except ValueError: raise ParseError("Invalid port") - allows_ports = {'https': True, 'http': True, 'ftp': True, - 'file': False, 'chrome': False, 'qute': False, - 'about': False, 'data': False, 'javascript': False, - None: True} - if not allows_ports[self._scheme] and self._port is not None: + if (self._scheme not in list(self.DEFAULT_PORTS) + [None] and + self._port is not None): raise ParseError("Ports are unsupported with {} scheme".format( self._scheme)) @@ -218,7 +220,9 @@ class UrlPattern: return host[len(host) - len(self._host) - 1] == '.' - def _matches_port(self, port): + def _matches_port(self, scheme, port): + if port == -1 and scheme in self.DEFAULT_PORTS: + port = self.DEFAULT_PORTS[scheme] return self._port is None or self._port == port def _matches_path(self, path): @@ -249,7 +253,7 @@ class UrlPattern: # FIXME ignore for file:// like Chromium? if not self._matches_host(qurl.host()): return False - if not self._matches_port(qurl.port()): + if not self._matches_port(qurl.scheme(), qurl.port()): return False if not self._matches_path(qurl.path()): return False diff --git a/tests/unit/utils/test_urlmatch.py b/tests/unit/utils/test_urlmatch.py index 7b0e754f3..b6f550bc8 100644 --- a/tests/unit/utils/test_urlmatch.py +++ b/tests/unit/utils/test_urlmatch.py @@ -311,3 +311,49 @@ class TestFileScheme: ]) def test_urls(self, up, url, expected): assert up.matches(QUrl(url)) == expected + + +class TestMatchSpecificPort: + + @pytest.fixture + def up(self): + return urlmatch.UrlPattern("http://www.example.com:80/foo") + + def test_attrs(self, up): + assert up._scheme == 'http' + assert up._host == 'www.example.com' + assert not up._match_subdomains + assert not up._match_all + assert up._path == '/foo' + assert up._port == 80 + + @pytest.mark.parametrize('url, expected', [ + ("http://www.example.com:80/foo", True), + ("http://www.example.com/foo", True), + ("http://www.example.com:8080/foo", False), + ]) + def test_urls(self, up, url, expected): + assert up.matches(QUrl(url)) == expected + + +class TestExplicitPortWildcard: + + @pytest.fixture + def up(self): + return urlmatch.UrlPattern("http://www.example.com:*/foo") + + def test_attrs(self, up): + assert up._scheme == 'http' + assert up._host == 'www.example.com' + assert not up._match_subdomains + assert not up._match_all + assert up._path == '/foo' + assert up._port is None + + @pytest.mark.parametrize('url, expected', [ + ("http://www.example.com:80/foo", True), + ("http://www.example.com/foo", True), + ("http://www.example.com:8080/foo", True), + ]) + def test_urls(self, up, url, expected): + assert up.matches(QUrl(url)) == expected