Ejemplo n.º 1
0
    def test_importlib(self, qt, qt5, expected, patch_elf_fail, importlib_patcher):
        """Test the importlib version logic with different Qt packages.

        With PyQtWebEngine 5.15.4, PyQtWebEngine-Qt was renamed to PyQtWebEngine-Qt5.
        """
        importlib_patcher(qt=qt, qt5=qt5)
        versions = version.qtwebengine_versions(avoid_init=True)
        assert versions.source == 'importlib'
        assert versions.webengine == expected
Ejemplo n.º 2
0
    def handle_download(self, qt_item):
        """Start a download coming from a QWebEngineProfile."""
        qt_filename = os.path.basename(qt_item.path())  # FIXME use 5.14 API
        mime_type = qt_item.mimeType()
        url = qt_item.url()

        # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-90355
        if version.qtwebengine_versions().webengine >= utils.VersionNumber(
                5, 15, 3):
            needs_workaround = False
        elif url.scheme().lower() == 'data':
            if '/' in url.path().split(',')[-1]:  # e.g. a slash in base64
                wrong_filename = url.path().split('/')[-1]
            else:
                wrong_filename = mime_type.split('/')[1]

            needs_workaround = qt_filename == wrong_filename
        else:
            needs_workaround = False

        if needs_workaround:
            suggested_filename = urlutils.filename_from_url(
                url, fallback='qutebrowser-download')
        else:
            suggested_filename = _strip_suffix(qt_filename)

        use_pdfjs = pdfjs.should_use_pdfjs(mime_type, url)

        download = DownloadItem(qt_item, manager=self)
        self._init_item(download,
                        auto_remove=use_pdfjs,
                        suggested_filename=suggested_filename)

        if self._mhtml_target is not None:
            download.set_target(self._mhtml_target)
            self._mhtml_target = None
            return
        if use_pdfjs:
            download.set_target(downloads.PDFJSDownloadTarget())
            return

        filename = downloads.immediate_download_path()
        if filename is not None:
            # User doesn't want to be asked, so just use the download_dir
            target = downloads.FileDownloadTarget(filename)
            download.set_target(target)
            return

        # Ask the user for a filename - needs to be blocking!
        question = downloads.get_filename_question(
            suggested_filename=suggested_filename,
            url=qt_item.url(),
            parent=self)
        self._init_filename_question(question, download)

        message.global_bridge.ask(question, blocking=True)
Ejemplo n.º 3
0
    def _qtwe_version_str(self) -> str:
        """Get the QtWebEngine version string.

        Note that it's too early to use objects.backend here...
        """
        try:
            import PyQt5.QtWebEngineWidgets  # pylint: disable=unused-import
        except ImportError:
            return 'no'
        return str(version.qtwebengine_versions(avoid_init=True).webengine)
Ejemplo n.º 4
0
def _qtwebengine_args(
    namespace: argparse.Namespace,
    special_flags: Sequence[str],
) -> Iterator[str]:
    """Get the QtWebEngine arguments to use based on the config."""
    versions = version.qtwebengine_versions(avoid_init=True)

    qt_514_ver = utils.VersionNumber(5, 14)
    qt_515_ver = utils.VersionNumber(5, 15)
    if qt_514_ver <= versions.webengine < qt_515_ver:
        # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-82105
        yield '--disable-shared-workers'

    # WORKAROUND equivalent to
    # https://codereview.qt-project.org/c/qt/qtwebengine/+/256786
    # also see:
    # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/265753
    if versions.webengine >= utils.VersionNumber(5, 12, 3):
        if 'stack' in namespace.debug_flags:
            # Only actually available in Qt 5.12.5, but let's save another
            # check, as passing the option won't hurt.
            yield '--enable-in-process-stack-traces'
    else:
        if 'stack' not in namespace.debug_flags:
            yield '--disable-in-process-stack-traces'

    if 'chromium' in namespace.debug_flags:
        yield '--enable-logging'
        yield '--v=1'

    if 'wait-renderer-process' in namespace.debug_flags:
        yield '--renderer-startup-dialog'

    from qutebrowser.browser.webengine import darkmode
    darkmode_settings = darkmode.settings(
        versions=versions,
        special_flags=special_flags,
    )
    for switch_name, values in darkmode_settings.items():
        # If we need to use other switches (say, --enable-features), we might need to
        # refactor this so values still get combined with existing ones.
        assert switch_name in ['dark-mode-settings',
                               'blink-settings'], switch_name
        yield f'--{switch_name}=' + ','.join(f'{k}={v}' for k, v in values)

    enabled_features, disabled_features = _qtwebengine_features(
        versions, special_flags)
    if enabled_features:
        yield _ENABLE_FEATURES + ','.join(enabled_features)
    if disabled_features:
        yield _DISABLE_FEATURES + ','.join(disabled_features)

    yield from _qtwebengine_settings_args(versions)
Ejemplo n.º 5
0
    def test_simulated(self, request, patches, sources):
        """Test various simulated error conditions.

        This dynamically gets a list of fixtures (above) to do the patching. It then
        checks whether the version it got is from one of the expected sources. Depending
        on the environment this test is run in, some sources might fail "naturally",
        i.e. without any patching related to them.
        """
        for patch in patches:
            request.getfixturevalue(f'patch_{patch}')

        versions = version.qtwebengine_versions(avoid_init=True)
        assert versions.source in sources
def _init_default_profile():
    """Init the default QWebEngineProfile."""
    global default_profile

    default_profile = QWebEngineProfile.defaultProfile()

    assert parsed_user_agent is None  # avoid earlier profile initialization
    non_ua_version = version.qtwebengine_versions(avoid_init=True)

    init_user_agent()
    ua_version = version.qtwebengine_versions()
    if ua_version.webengine != non_ua_version.webengine:
        log.init.warning(
            "QtWebEngine version mismatch - unexpected behavior might occur, "
            "please open a bug about this.\n"
            f"  Early version: {non_ua_version}\n"
            f"  Real version:  {ua_version}")

    default_profile.setCachePath(
        os.path.join(standarddir.cache(), 'webengine'))
    default_profile.setPersistentStoragePath(
        os.path.join(standarddir.data(), 'webengine'))

    _init_profile(default_profile)
Ejemplo n.º 7
0
    def _on_renderer_process_terminated(self, tab, status, code):
        """Show an error when a renderer process terminated."""
        if status == browsertab.TerminationStatus.normal:
            return

        messages = {
            browsertab.TerminationStatus.abnormal: "Renderer process exited",
            browsertab.TerminationStatus.crashed: "Renderer process crashed",
            browsertab.TerminationStatus.killed: "Renderer process was killed",
            browsertab.TerminationStatus.unknown:
            "Renderer process did not start",
        }
        msg = messages[status] + f" (status {code})"

        # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-91715
        versions = version.qtwebengine_versions()
        is_qtbug_91715 = (status == browsertab.TerminationStatus.unknown
                          and code == 1002
                          and versions.webengine == utils.VersionNumber(
                              5, 15, 3))

        def show_error_page(html):
            tab.set_html(html)
            log.webview.error(msg)

        if is_qtbug_91715:
            log.webview.error(msg)
            log.webview.error('')
            log.webview.error(
                'NOTE: If you see this and "Network service crashed, restarting '
                'service.", please see:')
            log.webview.error(
                'https://github.com/qutebrowser/qutebrowser/issues/6235')
            log.webview.error(
                'You can set the "qt.workarounds.locale" setting in qutebrowser to '
                'work around the issue.')
            log.webview.error(
                'A proper fix is likely available in QtWebEngine soon (which is why '
                'the workaround is disabled by default).')
            log.webview.error('')
        else:
            url_string = tab.url(requested=True).toDisplayString()
            error_page = jinja.render(
                'error.html',
                title="Error loading {}".format(url_string),
                url=url_string,
                error=msg)
            QTimer.singleShot(100, lambda: show_error_page(error_page))
Ejemplo n.º 8
0
def test_new_chromium():
    """Fail if we encounter an unknown Chromium version.

    Dark mode in Chromium (or rather, the underlying Blink) is being changed with
    almost every Chromium release.

    Make this test fail deliberately with newer Chromium versions, so that
    we can test whether dark mode still works manually, and adjust if not.
    """
    if version.webenginesettings is None:
        pytest.skip("QtWebKit not available")

    assert version.qtwebengine_versions().chromium in [
        '61.0.3163.140',  # Qt 5.10
        '65.0.3325.230',  # Qt 5.11
        '69.0.3497.128',  # Qt 5.12
        '73.0.3683.105',  # Qt 5.13
        '77.0.3865.129',  # Qt 5.14
        '80.0.3987.163',  # Qt 5.15.0
        '83.0.4103.122',  # Qt 5.15.2
    ]
Ejemplo n.º 9
0
 def test_avoided(self, monkeypatch):
     versions = version.qtwebengine_versions(avoid_init=True)
     assert versions.source in ['ELF', 'importlib', 'PyQt', 'Qt']
Ejemplo n.º 10
0
 def test_unpatched(self, qapp, cache_tmpdir, data_tmpdir, config_stub):
     assert version.qtwebengine_versions().chromium is not None
Ejemplo n.º 11
0
    def test_fake_ua(self, monkeypatch, caplog):
        ver = '77.0.3865.98'
        webenginesettings._init_user_agent_str(_QTWE_USER_AGENT.format(ver))

        assert version.qtwebengine_versions().chromium == ver
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
 def test_elf_fail_old_qt_simulated(self, monkeypatch):
     monkeypatch.setattr(elf, 'parse_webenginecore', lambda: None)
     monkeypatch.setattr(version, 'PYQT_WEBENGINE_VERSION_STR', None)
     versions = version.qtwebengine_versions(avoid_init=True)
     assert versions.source == 'Qt'
Ejemplo n.º 14
0
 def test_elf_fail_simulated(self, monkeypatch):
     monkeypatch.setattr(elf, 'parse_webenginecore', lambda: None)
     versions = version.qtwebengine_versions(avoid_init=True)
     assert versions.source in ['PyQt', 'Qt']