summaryrefslogtreecommitdiff
path: root/qutebrowser
diff options
context:
space:
mode:
authorAnder Punnar <ander@kvlt.ee>2021-06-01 20:36:56 +0300
committerAnder Punnar <ander@kvlt.ee>2021-06-01 20:36:56 +0300
commit00a394506f149b600c9869a63dd37e847fe17cfe (patch)
tree58c1ba094a79fa537abada91426cf2f01610c9c2 /qutebrowser
parent4e47af21586aad3846c2458dc0c8243e9d6eb792 (diff)
parentb34988055071522e72c73b0f3a0bd3a6b59c6b9a (diff)
downloadqutebrowser-00a394506f149b600c9869a63dd37e847fe17cfe.tar.gz
qutebrowser-00a394506f149b600c9869a63dd37e847fe17cfe.zip
Merge remote-tracking branch 'origin/master' into 4nd3r/hostblock_subdomains
Diffstat (limited to 'qutebrowser')
-rw-r--r--qutebrowser/__init__.py2
-rw-r--r--qutebrowser/browser/qutescheme.py5
-rw-r--r--qutebrowser/browser/webengine/notification.py34
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py14
-rw-r--r--qutebrowser/components/braveadblock.py10
-rw-r--r--qutebrowser/config/configdata.yml2
-rw-r--r--qutebrowser/config/configtypes.py41
-rw-r--r--qutebrowser/misc/editor.py2
-rw-r--r--qutebrowser/misc/quitter.py8
-rw-r--r--qutebrowser/utils/log.py16
10 files changed, 86 insertions, 48 deletions
diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py
index 96062d9bd..812df63c8 100644
--- a/qutebrowser/__init__.py
+++ b/qutebrowser/__init__.py
@@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2021 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
-__version__ = "2.2.2"
+__version__ = "2.2.3"
__version_info__ = tuple(int(part) for part in __version__.split('.'))
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."
diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py
index 031b6fe06..68e36d249 100644
--- a/qutebrowser/browser/qutescheme.py
+++ b/qutebrowser/browser/qutescheme.py
@@ -41,7 +41,7 @@ from qutebrowser.browser import pdfjs, downloads, history
from qutebrowser.config import config, configdata, configexc
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
resources, objreg, standarddir)
-from qutebrowser.misc import guiprocess
+from qutebrowser.misc import guiprocess, quitter
from qutebrowser.qt import sip
@@ -452,6 +452,9 @@ def qute_settings(url: QUrl) -> _HandlerRet:
if url.password() != csrf_token:
message.error("Invalid CSRF token for qute://settings!")
raise RequestDeniedError("Invalid CSRF token!")
+ if quitter.instance.is_shutting_down:
+ log.config.debug("Ignoring /set request during shutdown")
+ return 'text/html', b'error: ignored'
return _qute_settings_set(url)
# Requests to qute://settings/set should only be allowed from
diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py
index d8387e6d4..6b26157e6 100644
--- a/qutebrowser/browser/webengine/notification.py
+++ b/qutebrowser/browser/webengine/notification.py
@@ -65,12 +65,18 @@ if TYPE_CHECKING:
from qutebrowser.config import config
from qutebrowser.misc import objects
-from qutebrowser.utils import qtutils, log, utils, debug, message
+from qutebrowser.utils import qtutils, log, utils, debug, message, version
bridge: Optional['NotificationBridgePresenter'] = None
+def _notifications_supported() -> bool:
+ """Check whether the current QtWebEngine version has notification support."""
+ versions = version.qtwebengine_versions(avoid_init=True)
+ return versions.webengine >= utils.VersionNumber(5, 14)
+
+
def init() -> None:
"""Initialize the DBus notification presenter, if applicable.
@@ -84,7 +90,8 @@ def init() -> None:
# at a later point in time. However, doing so is probably too complex compared
# to its usefulness.
return
- if not qtutils.version_check('5.14'):
+
+ if not _notifications_supported():
return
global bridge
@@ -163,7 +170,7 @@ class NotificationBridgePresenter(QObject):
def __init__(self, parent: QObject = None) -> None:
super().__init__(parent)
- assert qtutils.version_check('5.14')
+ assert _notifications_supported()
self._active_notifications: Dict[int, 'QWebEngineNotification'] = {}
self._adapter: Optional[AbstractNotificationAdapter] = None
@@ -709,8 +716,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
def __init__(self, parent: QObject = None) -> None:
super().__init__(bridge)
- if not qtutils.version_check('5.14'):
- raise Error("Notifications are not supported on Qt < 5.14")
+ assert _notifications_supported()
if utils.is_windows:
# The QDBusConnection destructor seems to cause error messages (and
@@ -778,7 +784,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
self,
name: str,
vendor: str,
- version: str,
+ ver: str,
) -> Optional[_ServerQuirks]:
"""Find quirks to use based on the server information."""
if (name, vendor) == ("notify-osd", "Canonical Ltd"):
@@ -791,15 +797,15 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
# Still in active development but doesn't implement spec 1.2:
# https://github.com/mate-desktop/mate-notification-daemon/issues/132
quirks = _ServerQuirks(spec_version="1.1")
- if utils.VersionNumber.parse(version) <= utils.VersionNumber(1, 24):
+ if utils.VersionNumber.parse(ver) <= utils.VersionNumber(1, 24):
# https://github.com/mate-desktop/mate-notification-daemon/issues/118
quirks.avoid_body_hyperlinks = True
return quirks
- elif (name, vendor) == ("naughty", "awesome") and version != "devel":
+ elif (name, vendor) == ("naughty", "awesome") and ver != "devel":
# Still in active development but spec 1.0/1.2 support isn't
# released yet:
# https://github.com/awesomeWM/awesome/commit/e076bc664e0764a3d3a0164dabd9b58d334355f4
- parsed_version = utils.VersionNumber.parse(version.lstrip('v'))
+ parsed_version = utils.VersionNumber.parse(ver.lstrip('v'))
if parsed_version <= utils.VersionNumber(4, 3):
return _ServerQuirks(spec_version="1.0")
elif (name, vendor) == ("twmnd", "twmnd"):
@@ -810,7 +816,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
return _ServerQuirks(skip_capabilities=True)
elif (name, vendor) == ("lxqt-notificationd", "lxqt.org"):
quirks = _ServerQuirks()
- parsed_version = utils.VersionNumber.parse(version)
+ parsed_version = utils.VersionNumber.parse(ver)
if parsed_version <= utils.VersionNumber(0, 16):
# https://github.com/lxqt/lxqt-notificationd/issues/253
quirks.escape_title = True
@@ -843,13 +849,13 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
"""Query notification server information and set quirks."""
reply = self.interface.call(QDBus.BlockWithGui, "GetServerInformation")
self._verify_message(reply, "ssss", QDBusMessage.ReplyMessage)
- name, vendor, version, spec_version = reply.arguments()
+ name, vendor, ver, spec_version = reply.arguments()
log.misc.debug(
- f"Connected to notification server: {name} {version} by {vendor}, "
+ f"Connected to notification server: {name} {ver} by {vendor}, "
f"implementing spec {spec_version}")
- quirks = self._find_quirks(name, vendor, version)
+ quirks = self._find_quirks(name, vendor, ver)
if quirks is not None:
log.misc.debug(f"Enabling quirks {quirks}")
self._quirks = quirks
@@ -857,7 +863,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter):
expected_spec_version = self._quirks.spec_version or self.SPEC_VERSION
if spec_version != expected_spec_version:
log.misc.warning(
- f"Notification server ({name} {version} by {vendor}) implements "
+ f"Notification server ({name} {ver} by {vendor}) implements "
f"spec {spec_version}, but {expected_spec_version} was expected. "
f"If {name} is up to date, please report a qutebrowser bug.")
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index c793a1929..f9b636bde 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -401,6 +401,16 @@ class WebEngineCaret(browsertab.AbstractCaret):
self._js_call('reverseSelection')
def _follow_selected_cb_wrapped(self, js_elem, tab):
+ if sip.isdeleted(self):
+ # Sometimes, QtWebEngine JS callbacks seem to be stuck, and will
+ # later get executed when the tab is closed. However, at this point,
+ # the WebEngineCaret is already gone.
+ log.webview.warning(
+ "Got follow_selected callback for deleted WebEngineCaret. "
+ "This is most likely due to a QtWebEngine bug, please report a "
+ "qutebrowser issue if you know a way to reproduce this.")
+ return
+
try:
self._follow_selected_cb(js_elem, tab)
finally:
@@ -1593,7 +1603,9 @@ class WebEngineTab(browsertab.AbstractTab):
up doing it twice.
"""
super()._on_url_changed(url)
- if url.isValid() and qtutils.version_check('5.13'):
+ if (url.isValid() and
+ qtutils.version_check('5.13') and
+ not qtutils.version_check('5.14')):
self.settings.update_for_url(url)
@pyqtSlot(usertypes.NavigationRequest)
diff --git a/qutebrowser/components/braveadblock.py b/qutebrowser/components/braveadblock.py
index 0a39d5491..bd30f5d29 100644
--- a/qutebrowser/components/braveadblock.py
+++ b/qutebrowser/components/braveadblock.py
@@ -211,7 +211,15 @@ class BraveAdBlocker:
if cache_exists:
logger.debug("Loading cached adblock data: %s", self._cache_path)
- self._engine.deserialize_from_file(str(self._cache_path))
+ try:
+ self._engine.deserialize_from_file(str(self._cache_path))
+ except ValueError as e:
+ if str(e) != "DeserializationError":
+ # All Rust exceptions get turned into a ValueError by
+ # python-adblock
+ raise
+ message.error("Reading adblock filter data failed (corrupted data?). "
+ "Please run :adblock-update.")
else:
if (
config.val.content.blocking.adblock.lists
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index 80732d43d..b85e84be2 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -582,6 +582,7 @@ content.headers.accept_language:
type:
name: String
none_ok: true
+ encoding: ascii
supports_pattern: true
default: en-US,en;q=0.9
desc: >-
@@ -643,6 +644,7 @@ content.headers.user_agent:
Safari/{webkit_version}'
type:
name: FormatString
+ encoding: ascii
fields:
- os_info
- webkit_version
diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py
index c157fba41..d3d5e3fb8 100644
--- a/qutebrowser/config/configtypes.py
+++ b/qutebrowser/config/configtypes.py
@@ -86,6 +86,21 @@ _UnsetNone = Union[None, usertypes.Unset]
_StrUnsetNone = Union[str, _UnsetNone]
+def _validate_encoding(encoding: Optional[str], value: str) -> None:
+ """Check if the given value fits into the given encoding.
+
+ Raises ValidationError if not.
+ """
+ if encoding is None:
+ return
+
+ try:
+ value.encode(encoding)
+ except UnicodeEncodeError as e:
+ msg = f"{value!r} contains non-{encoding} characters: {e}"
+ raise configexc.ValidationError(value, msg)
+
+
class ValidValues:
"""Container for valid values for a given type.
@@ -377,6 +392,7 @@ class String(BaseType):
maxlen: Maximum length (inclusive).
forbidden: Forbidden chars in the string.
regex: A regex used to validate the string.
+ encoding: The encoding the value needs to fit in.
completions: completions to be used, or None
"""
@@ -407,24 +423,6 @@ class String(BaseType):
self.encoding = encoding
self.regex = regex
- def _validate_encoding(self, value: str) -> None:
- """Check if the given value fits into the configured encoding.
-
- Raises ValidationError if not.
-
- Args:
- value: The value to check.
- """
- if self.encoding is None:
- return
-
- try:
- value.encode(self.encoding)
- except UnicodeEncodeError as e:
- msg = "{!r} contains non-{} characters: {}".format(
- value, self.encoding, e)
- raise configexc.ValidationError(value, msg)
-
def to_py(self, value: _StrUnset) -> _StrUnsetNone:
self._basic_py_validation(value, str)
if isinstance(value, usertypes.Unset):
@@ -432,7 +430,7 @@ class String(BaseType):
elif not value:
return None
- self._validate_encoding(value)
+ _validate_encoding(self.encoding, value)
self._validate_valid_values(value)
if self.forbidden is not None and any(c in value
@@ -1544,6 +1542,7 @@ class FormatString(BaseType):
Attributes:
fields: Which replacements are allowed in the format string.
+ encoding: Which encoding the string should fit into.
completions: completions to be used, or None
"""
@@ -1551,11 +1550,13 @@ class FormatString(BaseType):
self, *,
fields: Iterable[str],
none_ok: bool = False,
+ encoding: str = None,
completions: _Completions = None,
) -> None:
super().__init__(
none_ok=none_ok, completions=completions)
self.fields = fields
+ self.encoding = encoding
self._completions = completions
def to_py(self, value: _StrUnset) -> _StrUnsetNone:
@@ -1565,6 +1566,8 @@ class FormatString(BaseType):
elif not value:
return None
+ _validate_encoding(self.encoding, value)
+
try:
value.format(**{k: '' for k in self.fields})
except (KeyError, IndexError, AttributeError) as e:
diff --git a/qutebrowser/misc/editor.py b/qutebrowser/misc/editor.py
index 5741c6b47..d561a7b96 100644
--- a/qutebrowser/misc/editor.py
+++ b/qutebrowser/misc/editor.py
@@ -131,7 +131,7 @@ class ExternalEditor(QObject):
raise ValueError("Already editing a file!")
try:
self._filename = self._create_tempfile(text, 'qutebrowser-editor-')
- except OSError as e:
+ except (OSError, UnicodeEncodeError) as e:
message.error("Failed to create initial file: {}".format(e))
return
diff --git a/qutebrowser/misc/quitter.py b/qutebrowser/misc/quitter.py
index 7d84c57f2..a51891685 100644
--- a/qutebrowser/misc/quitter.py
+++ b/qutebrowser/misc/quitter.py
@@ -54,7 +54,7 @@ class Quitter(QObject):
Attributes:
quit_status: The current quitting status.
- _is_shutting_down: Whether we're currently shutting down.
+ is_shutting_down: Whether we're currently shutting down.
_args: The argparse namespace.
"""
@@ -69,7 +69,7 @@ class Quitter(QObject):
'tabs': False,
'main': False,
}
- self._is_shutting_down = False
+ self.is_shutting_down = False
self._args = args
def on_last_window_closed(self) -> None:
@@ -214,9 +214,9 @@ class Quitter(QObject):
closing.
is_restart: If we're planning to restart.
"""
- if self._is_shutting_down:
+ if self.is_shutting_down:
return
- self._is_shutting_down = True
+ self.is_shutting_down = True
log.destroy.debug("Shutting down with status {}, session {}...".format(
status, session))
diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py
index b6f1f3e9b..9cd07e2e3 100644
--- a/qutebrowser/utils/log.py
+++ b/qutebrowser/utils/log.py
@@ -33,7 +33,7 @@ import json
import inspect
import argparse
from typing import (TYPE_CHECKING, Any, Iterator, Mapping, MutableSequence,
- Optional, Set, Tuple, Union, cast)
+ Optional, Set, Tuple, Union)
from PyQt5 import QtCore
# Optional imports
@@ -363,12 +363,16 @@ def change_console_formatter(level: int) -> None:
level: The numeric logging level
"""
assert console_handler is not None
+ old_formatter = console_handler.formatter
- old_formatter = cast(ColoredFormatter, console_handler.formatter)
- console_fmt = get_console_format(level)
- console_formatter = ColoredFormatter(console_fmt, DATEFMT, '{',
- use_colors=old_formatter.use_colors)
- console_handler.setFormatter(console_formatter)
+ if isinstance(old_formatter, ColoredFormatter):
+ console_fmt = get_console_format(level)
+ console_formatter = ColoredFormatter(
+ console_fmt, DATEFMT, '{', use_colors=old_formatter.use_colors)
+ console_handler.setFormatter(console_formatter)
+ else:
+ # Same format for all levels
+ assert isinstance(old_formatter, JSONFormatter), old_formatter
def qt_message_handler(msg_type: QtCore.QtMsgType,