Add qt.workarounds.remove_service_workers setting

See #5656, #5634
This commit is contained in:
Florian Bruhin 2021-01-27 14:06:21 +01:00
parent b0c812b239
commit 7d8fd50792
8 changed files with 112 additions and 8 deletions

View File

@ -94,6 +94,10 @@ Added
- New `:bookmark-list` command which lists all bookmarks/quickmarks. The
corresponding `qute://bookmarks` URL already existed since v0.8.0, but it was
never exposed as a command.
- New `qt.workarounds.remove_service_workers` setting which can be used to
remove the "Service Workers" directory on every start. Usage of this option is
generally discouraged, except in situations where the underlying QtWebEngine bug
is a known cause for crashes.
- New userscripts:
* `kodi` to play videos in Kodi
* `qr` to generate a QR code of the current URL

View File

@ -282,6 +282,7 @@
|<<qt.highdpi,qt.highdpi>>|Turn on Qt HighDPI scaling.
|<<qt.low_end_device_mode,qt.low_end_device_mode>>|When to use Chromium's low-end device mode.
|<<qt.process_model,qt.process_model>>|Which Chromium process model to use.
|<<qt.workarounds.remove_service_workers,qt.workarounds.remove_service_workers>>|Delete the QtWebEngine Service Worker directory on every start.
|<<scrolling.bar,scrolling.bar>>|When/how to show the scrollbar.
|<<scrolling.smooth,scrolling.smooth>>|Enable smooth scrolling for web pages.
|<<search.ignore_case,search.ignore_case>>|When to find text on a page case-insensitively.
@ -3638,6 +3639,16 @@ Default: +pass:[process-per-site-instance]+
This setting is only available with the QtWebEngine backend.
[[qt.workarounds.remove_service_workers]]
=== qt.workarounds.remove_service_workers
Delete the QtWebEngine Service Worker directory on every start.
This workaround can help with certain crashes caused by an unknown QtWebEngine bug related to Service Workers. Those crashes happen seemingly immediately on Windows; after one hour of operation on other systems.
Note however that enabling this option *can lead to data loss* on some pages (as Service Worker data isn't persisted) and will negatively impact start-up time.
Type: <<types,Bool>>
Default: +pass:[false]+
[[scrolling.bar]]
=== scrolling.bar
When/how to show the scrollbar.

View File

@ -286,6 +286,19 @@ qt.highdpi:
As an alternative to this, it's possible to set font sizes and the
`zoom.default` setting.
qt.workarounds.remove_service_workers:
type: Bool
default: false
desc: >-
Delete the QtWebEngine Service Worker directory on every start.
This workaround can help with certain crashes caused by an unknown QtWebEngine bug
related to Service Workers. Those crashes happen seemingly immediately on Windows;
after one hour of operation on other systems.
Note however that enabling this option *can lead to data loss* on some pages (as
Service Worker data isn't persisted) and will negatively impact start-up time.
## auto_save
auto_save.interval:

View File

@ -403,21 +403,22 @@ class _BackendProblemChecker:
# Nuke the service worker directory once for every install with Qt
# 5.14, given that it seems to cause a variety of segfaults.
configfiles.state['general']['serviceworker_workaround'] = '514'
affected = True
reason = 'Qt 5.14'
elif configfiles.state.qt_version_changed:
reason = 'Qt version changed'
elif config.val.qt.workarounds.remove_service_workers:
reason = 'Explicitly enabled'
else:
# Otherwise, just nuke it when the Qt version changed.
affected = configfiles.state.qt_version_changed
if not affected:
return
service_worker_dir = os.path.join(standarddir.data(), 'webengine',
'Service Worker')
service_worker_dir = os.path.join(
standarddir.data(), 'webengine', 'Service Worker')
bak_dir = service_worker_dir + '-bak'
if not os.path.exists(service_worker_dir):
return
log.init.info("Qt version changed, removing service workers")
log.init.info(
f"Removing service workers at {service_worker_dir} (reason: {reason})")
# Keep one backup around - we're not 100% sure what persistent data
# could be in there, but this folder can grow to ~300 MB.

View File

@ -0,0 +1 @@
{"foo": "bar"}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Service worker test</title>
<script>navigator.serviceWorker.register('worker.js')</script>
</head>
<body>
This page will register a service worker when loaded.
</body>
</html>

View File

@ -0,0 +1,8 @@
self.addEventListener('install', event => {
console.log("Installing service worker");
event.waitUntil(
caches.open('example-cache')
.then(cache => cache.add('data.json'))
.then(self.skipWaiting())
);
});

View File

@ -19,6 +19,7 @@
"""Test starting qutebrowser with special arguments/environments."""
import configparser
import subprocess
import sys
import logging
@ -435,3 +436,57 @@ def test_preferred_colorscheme(request, quteproc_new):
quteproc_new.send_cmd(':jseval matchMedia("(prefers-color-scheme: dark)").matches')
quteproc_new.wait_for(message='True')
@pytest.mark.qtwebkit_skip
@pytest.mark.parametrize('reason', [
'Explicitly enabled',
pytest.param('Qt 5.14', marks=utils.qt514),
'Qt version changed',
None,
])
def test_service_worker_workaround(
request, server, quteproc_new, short_tmpdir, reason):
"""Make sure we remove the QtWebEngine Service Worker directory if configured."""
args = _base_args(request.config) + ['--basedir', str(short_tmpdir)]
if reason == 'Explicitly enabled':
settings_args = ['-s', 'qt.workarounds.remove_service_workers', 'true']
else:
settings_args = []
service_worker_dir = short_tmpdir / 'data' / 'webengine' / 'Service Worker'
# First invocation: Create directory
quteproc_new.start(args)
quteproc_new.open_path('data/service-worker/index.html')
server.wait_for(verb='GET', path='/data/service-worker/data.json')
quteproc_new.send_cmd(':quit')
quteproc_new.wait_for_quit()
assert service_worker_dir.exists()
# Edit state file if needed
state_file = short_tmpdir / 'data' / 'state'
if reason == 'Qt 5.14':
state_file.remove()
elif reason == 'Qt version changed':
parser = configparser.ConfigParser()
parser.read(state_file)
del parser['general']['qt_version']
with state_file.open('w', encoding='utf-8') as f:
parser.write(f)
# Second invocation: Directory gets removed (if workaround enabled)
quteproc_new.start(args + settings_args)
if reason is not None:
quteproc_new.wait_for(
message=(f'Removing service workers at {service_worker_dir} '
f'(reason: {reason})'))
quteproc_new.send_cmd(':quit')
quteproc_new.wait_for_quit()
if reason is None:
assert service_worker_dir.exists()
quteproc_new.ensure_not_logged(message='Removing service workers at *')
else:
assert not service_worker_dir.exists()