From 3d53d0d2c53869705acd693aca41d1920cf65568 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 6 Jun 2018 23:08:14 +0200 Subject: [PATCH] Fix Qt 5.11 issues with clicking invalid links See #3661 --- qutebrowser/browser/webelem.py | 18 +++++++++++++++--- qutebrowser/browser/webengine/webview.py | 5 +++++ tests/unit/browser/webkit/test_webkitelem.py | 11 +++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index dee21c2d6..2f3499b4f 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -33,7 +33,8 @@ from PyQt5.QtGui import QMouseEvent from qutebrowser.config import config from qutebrowser.keyinput import modeman from qutebrowser.mainwindow import mainwindow -from qutebrowser.utils import log, usertypes, utils, qtutils, objreg +from qutebrowser.utils import (log, usertypes, utils, qtutils, objreg, + urlutils, message) Group = enum.Enum('Group', ['all', 'links', 'images', 'url', 'inputs']) @@ -275,11 +276,13 @@ class AbstractWebElement(collections.abc.MutableMapping): """Remove target from link.""" raise NotImplementedError - def resolve_url(self, baseurl): + def resolve_url(self, baseurl, *, return_invalid=False): """Resolve the URL in the element's src/href attribute. Args: baseurl: The URL to base relative URLs on as QUrl. + return_invalid: Whether to return an invalid QUrl. + If False, None is returned for invalid URLs. Return: A QUrl with the absolute URL, or None. @@ -296,7 +299,7 @@ class AbstractWebElement(collections.abc.MutableMapping): url = QUrl(text) if not url.isValid(): - return None + return url if return_invalid else None if url.isRelative(): url = baseurl.resolved(url) qtutils.ensure_valid(url) @@ -404,6 +407,15 @@ class AbstractWebElement(collections.abc.MutableMapping): self._click_fake_event(click_target) return + if qtutils.version_check('5.11', compiled=False): + # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-63378 + baseurl = self._tab.url() + url = self.resolve_url(baseurl, return_invalid=True) + if url is not None and not url.isValid(): + msg = urlutils.get_errstring(url, "Invalid link clicked") + message.error(msg) + return + if click_target == usertypes.ClickTarget.normal: if self.is_link(): log.webelem.debug("Clicking via JS click()") diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index 969e3c7ec..20689bd2a 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -342,6 +342,11 @@ class WebEnginePage(QWebEnginePage): navigation_type=type_map[typ], is_main_frame=is_main_frame) self.navigation_request.emit(navigation) + + if not url.isValid() and qtutils.version_check('5.11', compiled=False): + # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-63378 + return True + return navigation.accepted @pyqtSlot('QUrl') diff --git a/tests/unit/browser/webkit/test_webkitelem.py b/tests/unit/browser/webkit/test_webkitelem.py index df3de6310..d4ad7f008 100644 --- a/tests/unit/browser/webkit/test_webkitelem.py +++ b/tests/unit/browser/webkit/test_webkitelem.py @@ -872,3 +872,14 @@ def test_resolve_url_relative_base(): elem = get_webelem(attributes={'href': 'foo'}) with pytest.raises(ValueError): elem.resolve_url(QUrl('base')) + + +@pytest.mark.parametrize('return_invalid', [True, False]) +def test_resolve_url_invalid(return_invalid): + elem = get_webelem(attributes={'href': 'what://::'}) + baseurl = QUrl('http://www.example.com/') + resolved = elem.resolve_url(baseurl, return_invalid=return_invalid) + if return_invalid: + assert not resolved.isValid() + else: + assert resolved is None