Beispiel #1
0
    def _verify_message(
        self,
        msg: QDBusMessage,
        expected_signature: str,
        expected_type: QDBusMessage.MessageType,
    ) -> None:
        """Check the signature/type of a received message.

        Raises DBusError if the signature doesn't match.
        """
        assert expected_type not in [
            QDBusMessage.ErrorMessage,
            QDBusMessage.InvalidMessage,
        ], expected_type

        if msg.type() == QDBusMessage.ErrorMessage:
            raise DBusError(msg)

        signature = msg.signature()
        if signature != expected_signature:
            raise Error(
                f"Got a message with signature {signature} but expected "
                f"{expected_signature} (args: {msg.arguments()})")

        typ = msg.type()
        if typ != expected_type:
            type_str = debug.qenum_key(QDBusMessage.MessageType, typ)
            expected_type_str = debug.qenum_key(QDBusMessage.MessageType,
                                                expected_type)
            raise Error(
                f"Got a message of type {type_str} but expected {expected_type_str}"
                f"(args: {msg.arguments()})")
Beispiel #2
0
    def interceptRequest(self, info):
        """Handle the given request.

        Reimplementing this virtual function and setting the interceptor on a
        profile makes it possible to intercept URL requests. This function is
        executed on the IO thread, and therefore running long tasks here will
        block networking.

        info contains the information about the URL request and will track
        internally whether its members have been altered.

        Args:
            info: QWebEngineUrlRequestInfo &info
        """
        if 'log-requests' in self._args.debug_flags:
            resource_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                            info.resourceType())
            navigation_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                              info.navigationType())
            log.webview.debug("{} {}, first-party {}, resource {}, "
                              "navigation {}".format(
                                  bytes(info.requestMethod()).decode('ascii'),
                                  info.requestUrl().toDisplayString(),
                                  info.firstPartyUrl().toDisplayString(),
                                  resource_type, navigation_type))

        url = info.requestUrl()
        first_party = info.firstPartyUrl()

        if ((url.scheme(), url.host(), url.path()) ==
                ('qute', 'settings', '/set')):
            if (first_party != QUrl('qute://settings/') or
                    info.resourceType() !=
                    QWebEngineUrlRequestInfo.ResourceTypeXhr):
                log.webview.warning("Blocking malicious request from {} to {}"
                                    .format(first_party.toDisplayString(),
                                            url.toDisplayString()))
                info.block(True)
                return

        # FIXME:qtwebengine only block ads for NavigationTypeOther?
        request = interceptors.Request(first_party_url=first_party,
                                       request_url=url)
        interceptors.run(request)
        if request.is_blocked:
            info.block(True)

        for header, value in shared.custom_headers(url=url):
            info.setHttpHeader(header, value)

        user_agent = config.instance.get('content.headers.user_agent', url=url)
        if user_agent is not None:
            info.setHttpHeader(b'User-Agent', user_agent.encode('ascii'))
Beispiel #3
0
    def interceptRequest(self, info):
        """Handle the given request.

        Reimplementing this virtual function and setting the interceptor on a
        profile makes it possible to intercept URL requests. This function is
        executed on the IO thread, and therefore running long tasks here will
        block networking.

        info contains the information about the URL request and will track
        internally whether its members have been altered.

        Args:
            info: QWebEngineUrlRequestInfo &info
        """
        if 'log-requests' in self._args.debug_flags:
            resource_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                            info.resourceType())
            navigation_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                              info.navigationType())
            log.webview.debug("{} {}, first-party {}, resource {}, "
                              "navigation {}".format(
                                  bytes(info.requestMethod()).decode('ascii'),
                                  info.requestUrl().toDisplayString(),
                                  info.firstPartyUrl().toDisplayString(),
                                  resource_type, navigation_type))

        url = info.requestUrl()
        first_party = info.firstPartyUrl()

        if ((url.scheme(), url.host(), url.path()) == ('qute', 'settings',
                                                       '/set')):
            if (first_party != QUrl('qute://settings/') or info.resourceType()
                    != QWebEngineUrlRequestInfo.ResourceTypeXhr):
                log.webview.warning(
                    "Blocking malicious request from {} to {}".format(
                        first_party.toDisplayString(), url.toDisplayString()))
                info.block(True)
                return

        # FIXME:qtwebengine only block ads for NavigationTypeOther?
        request = interceptors.Request(first_party_url=first_party,
                                       request_url=url)
        interceptors.run(request)
        if request.is_blocked:
            info.block(True)

        for header, value in shared.custom_headers(url=url):
            info.setHttpHeader(header, value)

        user_agent = config.instance.get('content.headers.user_agent', url=url)
        if user_agent is not None:
            info.setHttpHeader(b'User-Agent', user_agent.encode('ascii'))
Beispiel #4
0
def _log_error(error):
    """Log informations about a SQL error to the debug log."""
    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(error.databaseText()))
    log.sql.debug("driver text: {}".format(error.driverText()))
    log.sql.debug("error code: {}".format(error.nativeErrorCode()))
Beispiel #5
0
def raise_sqlite_error(msg, error):
    """Raise either a SqlBugError or SqlEnvironmentError."""
    error_code = error.nativeErrorCode()
    database_text = error.databaseText()
    driver_text = error.driverText()

    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(
        debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(database_text))
    log.sql.debug("driver text: {}".format(driver_text))
    log.sql.debug("error code: {}".format(error_code))

    environmental_errors = [
        SqliteErrorCode.BUSY,
        SqliteErrorCode.READONLY,
        SqliteErrorCode.IOERR,
        SqliteErrorCode.CORRUPT,
        SqliteErrorCode.FULL,
        SqliteErrorCode.CANTOPEN,
    ]

    # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70506
    # We don't know what the actual error was, but let's assume it's not us to
    # blame... Usually this is something like an unreadable database file.
    qtbug_70506 = (error_code == SqliteErrorCode.UNKNOWN and
                   driver_text == "Error opening database" and
                   database_text == "out of memory")

    if error_code in environmental_errors or qtbug_70506:
        raise SqlEnvironmentError(msg, error)
    else:
        raise SqlBugError(msg, error)
Beispiel #6
0
    def __init__(self, msg, error):
        super().__init__(msg)
        self.error = error

        log.sql.debug("SQL error:")
        log.sql.debug("type: {}".format(
            debug.qenum_key(QSqlError, error.type())))
        log.sql.debug("database text: {}".format(error.databaseText()))
        log.sql.debug("driver text: {}".format(error.driverText()))
        log.sql.debug("error code: {}".format(error.nativeErrorCode()))

        # https://sqlite.org/rescode.html
        # https://github.com/qutebrowser/qutebrowser/issues/2930
        # https://github.com/qutebrowser/qutebrowser/issues/3004
        environmental_errors = [
            '5',  # SQLITE_BUSY ("database is locked")
            '8',  # SQLITE_READONLY
            '11',  # SQLITE_CORRUPT
            '13',  # SQLITE_FULL
        ]
        # At least in init(), we can get errors like this:
        # type: ConnectionError
        # database text: out of memory
        # driver text: Error opening database
        # error code: -1
        environmental_strings = [
            "out of memory",
        ]
        errcode = error.nativeErrorCode()
        self.environmental = (
            errcode in environmental_errors or
            (errcode == -1 and error.databaseText() in environmental_strings))
Beispiel #7
0
    def acceptNavigationRequest(self, url: QUrl,
                                typ: QWebEnginePage.NavigationType,
                                is_main_frame: bool):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then conditionally opens the URL. Opening it in a new tab/window
        is handled in the slot connected to link_clicked.
        """
        target = self._tabdata.combined_target()
        log.webview.debug("navigation request: url {}, type {}, "
                          "target {}, is_main_frame {}".format(
                              url.toDisplayString(),
                              debug.qenum_key(QWebEnginePage, typ), target,
                              is_main_frame))

        if typ != QWebEnginePage.NavigationTypeLinkClicked:
            return True

        self.link_clicked.emit(url)

        return url.isValid() and target == usertypes.ClickTarget.normal
Beispiel #8
0
    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebPage, each time the page wants to create a new window of
        the given type. This might be the result, for example, of a JavaScript
        request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebPage::WebBrowserWindow: The window is a regular web
                                                 browser window.
                     QWebPage::WebModalDialog: The window acts as modal dialog.

        Return:
            The new QWebView object.
        """
        debug_type = debug.qenum_key(QWebPage, wintype)
        log.webview.debug("createWindow with type {}".format(debug_type))
        if wintype == QWebPage.WebModalDialog:
            log.webview.warning("WebModalDialog requested, but we don't "
                                "support that!")
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self.win_id)
        # pylint: disable=protected-access
        return tabbed_browser.tabopen(background=False)._widget
    def _on_state_changed(self, state):
        state_name = debug.qenum_key(QWebEngineDownloadItem, state)
        log.downloads.debug("State for {!r} changed to {}".format(
            self, state_name))

        if state == QWebEngineDownloadItem.DownloadRequested:
            pass
        elif state == QWebEngineDownloadItem.DownloadInProgress:
            pass
        elif state == QWebEngineDownloadItem.DownloadCompleted:
            log.downloads.debug("Download {} finished".format(self.basename))
            self.successful = True
            self.done = True
            self.finished.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadCancelled:
            self.successful = False
            self.done = True
            self.cancelled.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadInterrupted:
            self.successful = False
            self.done = True
            # https://bugreports.qt.io/browse/QTBUG-56839
            self.error.emit("Download failed")
            self.stats.finish()
        else:
            raise ValueError("_on_state_changed was called with unknown state "
                             "{}".format(state_name))
Beispiel #10
0
def _writable_location(typ):
    """Wrapper around QStandardPaths.writableLocation.

    Arguments:
        typ: A QStandardPaths::StandardLocation member.
    """
    typ_str = debug.qenum_key(QStandardPaths, typ)

    # Types we are sure we handle correctly below.
    assert typ in [
        QStandardPaths.ConfigLocation, QStandardPaths.DataLocation,
        QStandardPaths.CacheLocation, QStandardPaths.DownloadLocation,
        QStandardPaths.RuntimeLocation, QStandardPaths.TempLocation,
        # FIXME old Qt
        getattr(QStandardPaths, 'AppDataLocation', object())], typ_str

    with _unset_organization():
        path = QStandardPaths.writableLocation(typ)

    log.misc.debug("writable location for {}: {}".format(typ_str, path))
    if not path:
        raise EmptyValueError("QStandardPaths returned an empty value!")

    # Qt seems to use '/' as path separator even on Windows...
    path = path.replace('/', os.sep)

    # Add the application name to the given path if needed.
    # This is in order for this to work without a QApplication (and thus
    # QStandardsPaths not knowing the application name), as well as a
    # workaround for https://bugreports.qt.io/browse/QTBUG-38872
    if (typ != QStandardPaths.DownloadLocation and
            path.split(os.sep)[-1] != APPNAME):
        path = os.path.join(path, APPNAME)

    return path
Beispiel #11
0
    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebPage, each time the page wants to create a new window of
        the given type. This might be the result, for example, of a JavaScript
        request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebPage::WebBrowserWindow: The window is a regular web
                                                 browser window.
                     QWebPage::WebModalDialog: The window acts as modal dialog.

        Return:
            The new QWebView object.
        """
        debug_type = debug.qenum_key(QWebPage, wintype)
        log.webview.debug("createWindow with type {}".format(debug_type))
        if wintype == QWebPage.WebModalDialog:
            log.webview.warning("WebModalDialog requested, but we don't "
                                "support that!")
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self.win_id)
        # pylint: disable=protected-access
        return tabbed_browser.tabopen(background=False)._widget
Beispiel #12
0
    def __init__(self, msg, error):
        super().__init__(msg)
        self.error = error

        log.sql.debug("SQL error:")
        log.sql.debug("type: {}".format(
            debug.qenum_key(QSqlError, error.type())))
        log.sql.debug("database text: {}".format(error.databaseText()))
        log.sql.debug("driver text: {}".format(error.driverText()))
        log.sql.debug("error code: {}".format(error.nativeErrorCode()))

        # https://sqlite.org/rescode.html
        # https://github.com/qutebrowser/qutebrowser/issues/2930
        # https://github.com/qutebrowser/qutebrowser/issues/3004
        environmental_errors = [
            '5',   # SQLITE_BUSY ("database is locked")
            '8',   # SQLITE_READONLY
            '11',  # SQLITE_CORRUPT
            '13',  # SQLITE_FULL
        ]
        # At least in init(), we can get errors like this:
        # type: ConnectionError
        # database text: out of memory
        # driver text: Error opening database
        # error code: -1
        environmental_strings = [
            "out of memory",
        ]
        errcode = error.nativeErrorCode()
        self.environmental = (
            errcode in environmental_errors or
            (errcode == -1 and error.databaseText() in environmental_strings))
    def createRequest(self, op, req, outgoing_data):
        """Return a new QNetworkReply object.

        Args:
             op: Operation op
             req: const QNetworkRequest & req
             outgoing_data: QIODevice * outgoingData

        Return:
            A QNetworkReply.
        """
        if proxymod.application_factory is not None:
            proxy_error = proxymod.application_factory.get_error()
            if proxy_error is not None:
                return networkreply.ErrorNetworkReply(
                    req, proxy_error, QNetworkReply.UnknownProxyError, self)

        if not req.url().isValid():
            log.network.debug("Ignoring invalid requested URL: {}".format(
                req.url().errorString()))
            return networkreply.ErrorNetworkReply(
                req, "Invalid request URL", QNetworkReply.HostNotFoundError,
                self)

        for header, value in shared.custom_headers(url=req.url()):
            req.setRawHeader(header, value)

        tab = self._get_tab()
        current_url = QUrl()
        if tab is not None:
            try:
                current_url = tab.url()
            except RuntimeError:
                # We could be in the middle of the webpage shutdown here.
                pass

        request = interceptors.Request(first_party_url=current_url,
                                       request_url=req.url())
        interceptors.run(request)
        if request.is_blocked:
            return networkreply.ErrorNetworkReply(
                req, HOSTBLOCK_ERROR_STRING, QNetworkReply.ContentAccessDenied,
                self)

        if 'log-requests' in objects.debug_flags:
            operation = debug.qenum_key(QNetworkAccessManager, op)
            operation = operation.replace('Operation', '').upper()
            log.network.debug("{} {}, first-party {}".format(
                operation,
                req.url().toDisplayString(), current_url.toDisplayString()))

        scheme = req.url().scheme()
        if scheme in self._scheme_handlers:
            result = self._scheme_handlers[scheme](req, op, current_url)
            if result is not None:
                result.setParent(self)
                return result

        self.set_referer(req, current_url)
        return super().createRequest(op, req, outgoing_data)
Beispiel #14
0
def raise_sqlite_error(msg, error):
    """Raise either a SqlBugError or SqlEnvironmentError."""
    error_code = error.nativeErrorCode()
    database_text = error.databaseText()
    driver_text = error.driverText()

    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(
        debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(database_text))
    log.sql.debug("driver text: {}".format(driver_text))
    log.sql.debug("error code: {}".format(error_code))

    environmental_errors = [
        SqliteErrorCode.BUSY,
        SqliteErrorCode.READONLY,
        SqliteErrorCode.IOERR,
        SqliteErrorCode.CORRUPT,
        SqliteErrorCode.FULL,
        SqliteErrorCode.CANTOPEN,
    ]

    # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70506
    # We don't know what the actual error was, but let's assume it's not us to
    # blame... Usually this is something like an unreadable database file.
    qtbug_70506 = (error_code == SqliteErrorCode.UNKNOWN and
                   driver_text == "Error opening database" and
                   database_text == "out of memory")

    if error_code in environmental_errors or qtbug_70506:
        raise SqlEnvironmentError(msg, error)
    else:
        raise SqlBugError(msg, error)
    def _on_state_changed(self, state):
        state_name = debug.qenum_key(QWebEngineDownloadItem, state)
        log.downloads.debug("State for {!r} changed to {}".format(
            self, state_name))

        if state == QWebEngineDownloadItem.DownloadRequested:
            pass
        elif state == QWebEngineDownloadItem.DownloadInProgress:
            pass
        elif state == QWebEngineDownloadItem.DownloadCompleted:
            log.downloads.debug("Download {} finished".format(self.basename))
            if self._is_page_download():
                # Same logging as QtWebKit mhtml downloads.
                log.downloads.debug("File successfully written.")
            self.successful = True
            self.done = True
            self.finished.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadCancelled:
            self.successful = False
            self.done = True
            self.cancelled.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadInterrupted:
            self.successful = False
            # https://bugreports.qt.io/browse/QTBUG-56839
            try:
                reason = self._qt_item.interruptReasonString()
            except AttributeError:
                # Qt < 5.9
                reason = "Download failed"
            self._die(reason)
        else:
            raise ValueError("_on_state_changed was called with unknown state "
                             "{}".format(state_name))
Beispiel #16
0
    def acceptNavigationRequest(self,
                                url: QUrl,
                                typ: QWebEnginePage.NavigationType,
                                is_main_frame: bool):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then conditionally opens the URL. Opening it in a new tab/window
        is handled in the slot connected to link_clicked.
        """
        target = self._tabdata.combined_target()
        log.webview.debug("navigation request: url {}, type {}, "
                          "target {}, is_main_frame {}".format(
                              url.toDisplayString(),
                              debug.qenum_key(QWebEnginePage, typ),
                              target, is_main_frame))

        if typ != QWebEnginePage.NavigationTypeLinkClicked:
            return True

        self.link_clicked.emit(url)

        return url.isValid() and target == usertypes.ClickTarget.normal
 def _ensure_can_set_filename(self, filename):
     state = self._qt_item.state()
     if state != QWebEngineDownloadItem.DownloadRequested:
         state_name = debug.qenum_key(QWebEngineDownloadItem, state)
         raise ValueError("Trying to set filename {} on {!r} which is "
                          "state {} (not in requested state)!".format(
                              filename, self, state_name))
 def __repr__(self) -> str:
     return utils.get_repr(self,
                           errors=[
                               debug.qenum_key(QSslError, err.error())
                               for err in self._errors
                           ],
                           string=str(self))
Beispiel #19
0
def raise_sqlite_error(msg, error):
    """Raise either a BugError or KnownError."""
    error_code = error.nativeErrorCode()
    database_text = error.databaseText()
    driver_text = error.driverText()

    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(database_text))
    log.sql.debug("driver text: {}".format(driver_text))
    log.sql.debug("error code: {}".format(error_code))

    known_errors = [
        SqliteErrorCode.BUSY,
        SqliteErrorCode.READONLY,
        SqliteErrorCode.IOERR,
        SqliteErrorCode.CORRUPT,
        SqliteErrorCode.FULL,
        SqliteErrorCode.CANTOPEN,
        SqliteErrorCode.PROTOCOL,
        SqliteErrorCode.NOTADB,
    ]

    # https://github.com/qutebrowser/qutebrowser/issues/4681
    # If the query we built was too long
    too_long_err = (
        error_code == SqliteErrorCode.ERROR and
        (database_text.startswith("Expression tree is too large")
         or database_text
         in ["too many SQL variables", "LIKE or GLOB pattern too complex"]))

    if error_code in known_errors or too_long_err:
        raise KnownError(msg, error)

    raise BugError(msg, error)
Beispiel #20
0
def raise_sqlite_error(msg, error):
    """Raise either a SqlBugError or SqlEnvironmentError."""
    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(
        debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(error.databaseText()))
    log.sql.debug("driver text: {}".format(error.driverText()))
    log.sql.debug("error code: {}".format(error.nativeErrorCode()))
    environmental_errors = [
        SqliteErrorCode.BUSY,
        SqliteErrorCode.READONLY,
        SqliteErrorCode.IOERR,
        SqliteErrorCode.CORRUPT,
        SqliteErrorCode.FULL,
        SqliteErrorCode.CANTOPEN,
    ]
    # At least in init(), we can get errors like this:
    # > type: ConnectionError
    # > database text: out of memory
    # > driver text: Error opening database
    # > error code: -1
    environmental_strings = [
        "out of memory",
    ]
    errcode = error.nativeErrorCode()
    if (errcode in environmental_errors or
            (errcode == -1 and error.databaseText() in environmental_strings)):
        raise SqlEnvironmentError(msg, error)
    else:
        raise SqlBugError(msg, error)
    def _on_state_changed(self, state):
        state_name = debug.qenum_key(QWebEngineDownloadItem, state)
        log.downloads.debug("State for {!r} changed to {}".format(
            self, state_name))

        if state == QWebEngineDownloadItem.DownloadRequested:
            pass
        elif state == QWebEngineDownloadItem.DownloadInProgress:
            pass
        elif state == QWebEngineDownloadItem.DownloadCompleted:
            log.downloads.debug("Download {} finished".format(self.basename))
            if self._is_page_download():
                # Same logging as QtWebKit mhtml downloads.
                log.downloads.debug("File successfully written.")
            self.successful = True
            self.done = True
            self.finished.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadCancelled:
            self.successful = False
            self.done = True
            self.cancelled.emit()
            self.stats.finish()
        elif state == QWebEngineDownloadItem.DownloadInterrupted:
            self.successful = False
            # https://bugreports.qt.io/browse/QTBUG-56839
            try:
                reason = self._qt_item.interruptReasonString()
            except AttributeError:
                # Qt < 5.9
                reason = "Download failed"
            self._die(reason)
        else:
            raise ValueError("_on_state_changed was called with unknown state "
                             "{}".format(state_name))
 def _ensure_can_set_filename(self, filename):
     state = self._qt_item.state()
     if state != QWebEngineDownloadItem.DownloadRequested:
         state_name = debug.qenum_key(QWebEngineDownloadItem, state)
         raise ValueError("Trying to set filename {} on {!r} which is "
                          "state {} (not in requested state)!".format(
                              filename, self, state_name))
Beispiel #23
0
def _writable_location(typ: QStandardPaths.StandardLocation) -> str:
    """Wrapper around QStandardPaths.writableLocation.

    Arguments:
        typ: A QStandardPaths::StandardLocation member.
    """
    typ_str = debug.qenum_key(QStandardPaths, typ)

    # Types we are sure we handle correctly below.
    assert typ in [
        QStandardPaths.ConfigLocation, QStandardPaths.AppLocalDataLocation,
        QStandardPaths.CacheLocation, QStandardPaths.DownloadLocation,
        QStandardPaths.RuntimeLocation, QStandardPaths.TempLocation,
        QStandardPaths.AppDataLocation
    ], typ_str

    with _unset_organization():
        path = QStandardPaths.writableLocation(typ)

    log.misc.debug("writable location for {}: {}".format(typ_str, path))
    if not path:
        raise EmptyValueError("QStandardPaths returned an empty value!")

    # Qt seems to use '/' as path separator even on Windows...
    path = path.replace('/', os.sep)

    # Add the application name to the given path if needed.
    # This is in order for this to work without a QApplication (and thus
    # QStandardsPaths not knowing the application name).
    if (typ != QStandardPaths.DownloadLocation
            and path.split(os.sep)[-1] != APPNAME):
        path = os.path.join(path, APPNAME)

    return path
Beispiel #24
0
 def _do_cancel(self):
     state = self._qt_item.state()
     state_name = debug.qenum_key(QWebEngineDownloadItem, state)
     assert state not in [
         QWebEngineDownloadItem.DownloadCompleted,
         QWebEngineDownloadItem.DownloadCancelled
     ], state_name
     self._qt_item.cancel()
Beispiel #25
0
 def test_no_metaobj(self):
     """Test with an enum with no metaobject."""
     with self.assertRaises(AttributeError):
         # Make sure it doesn't have a meta object
         # pylint: disable=pointless-statement,no-member
         QStyle.PrimitiveElement.staticMetaObject
     key = debug.qenum_key(QStyle, QStyle.PE_PanelButtonCommand)
     self.assertEqual(key, 'PE_PanelButtonCommand')
Beispiel #26
0
 def test_no_metaobj(self):
     """Test with an enum with no metaobject."""
     with self.assertRaises(AttributeError):
         # Make sure it doesn't have a meta object
         # pylint: disable=pointless-statement,no-member
         QStyle.PrimitiveElement.staticMetaObject
     key = debug.qenum_key(QStyle, QStyle.PE_PanelButtonCommand)
     self.assertEqual(key, 'PE_PanelButtonCommand')
Beispiel #27
0
    def _on_feature_permission_requested(self, url, feature):
        """Ask the user for approval for geolocation/media/etc.."""
        options = {
            QWebEnginePage.Geolocation: 'content.geolocation',
            QWebEnginePage.MediaAudioCapture: 'content.media_capture',
            QWebEnginePage.MediaVideoCapture: 'content.media_capture',
            QWebEnginePage.MediaAudioVideoCapture: 'content.media_capture',
        }
        messages = {
            QWebEnginePage.Geolocation: 'access your location',
            QWebEnginePage.MediaAudioCapture: 'record audio',
            QWebEnginePage.MediaVideoCapture: 'record video',
            QWebEnginePage.MediaAudioVideoCapture: 'record audio/video',
        }
        try:
            options.update({
                QWebEnginePage.DesktopVideoCapture:
                'content.desktop_capture',
                QWebEnginePage.DesktopAudioVideoCapture:
                'content.desktop_capture',
            })
            messages.update({
                QWebEnginePage.DesktopVideoCapture:
                'capture your desktop',
                QWebEnginePage.DesktopAudioVideoCapture:
                'capture your desktop and audio',
            })
        except AttributeError:
            # Added in Qt 5.10
            pass

        assert options.keys() == messages.keys()

        page = self._widget.page()

        if feature not in options:
            log.webview.error("Unhandled feature permission {}".format(
                debug.qenum_key(QWebEnginePage, feature)))
            page.setFeaturePermission(url, feature,
                                      QWebEnginePage.PermissionDeniedByUser)
            return

        yes_action = functools.partial(page.setFeaturePermission, url, feature,
                                       QWebEnginePage.PermissionGrantedByUser)
        no_action = functools.partial(page.setFeaturePermission, url, feature,
                                      QWebEnginePage.PermissionDeniedByUser)

        question = shared.feature_permission(url=url,
                                             option=options[feature],
                                             msg=messages[feature],
                                             yes_action=yes_action,
                                             no_action=no_action,
                                             abort_on=[self._abort_questions])

        if question is not None:
            page.featurePermissionRequestCanceled.connect(
                functools.partial(self._on_feature_permission_cancelled,
                                  question, url, feature))
Beispiel #28
0
 def __repr__(self):
     if self.modifiers is None:
         modifiers = None
     else:
         #modifiers = qflags_key(Qt, self.modifiers)
         modifiers = hex(int(self.modifiers))
     return get_repr(self, constructor=True,
                     key=debug.qenum_key(Qt, self.key),
                     modifiers=modifiers, text=self.text)
Beispiel #29
0
 def __repr__(self):
     if self.modifiers is None:
         modifiers = None
     else:
         #modifiers = qflags_key(Qt, self.modifiers)
         modifiers = hex(int(self.modifiers))
     return get_repr(self, constructor=True,
                     key=debug.qenum_key(Qt, self.key),
                     modifiers=modifiers, text=self.text)
Beispiel #30
0
    def retry(self):
        state = self._qt_item.state()
        if state != QWebEngineDownloadItem.DownloadInterrupted:
            log.downloads.warning(
                "Refusing to retry download in state {}".format(
                    debug.qenum_key(QWebEngineDownloadItem, state)))
            return

        self._qt_item.resume()
Beispiel #31
0
    def acceptNavigationRequest(self, _frame, request, typ):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then opens the URL.

        Args:
            _frame: QWebFrame (target frame)
            request: QNetworkRequest
            typ: QWebPage::NavigationType
        """
        url = request.url()
        urlstr = url.toDisplayString()
        if typ == QWebPage.NavigationTypeReload:
            self.reloading.emit(url)
        if typ != QWebPage.NavigationTypeLinkClicked:
            return True
        if not url.isValid():
            message.error(self._win_id,
                          "Invalid link {} clicked!".format(urlstr))
            log.webview.debug(url.errorString())
            self.open_target = usertypes.ClickTarget.normal
            return False
        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        log.webview.debug("acceptNavigationRequest, url {}, type {}, hint "
                          "target {}, open_target {}".format(
                              urlstr, debug.qenum_key(QWebPage, typ),
                              self._hint_target, self.open_target))
        if self._hint_target is not None:
            target = self._hint_target
        else:
            target = self.open_target
        self.open_target = usertypes.ClickTarget.normal
        if target == usertypes.ClickTarget.tab:
            tabbed_browser.tabopen(url, False)
            return False
        elif target == usertypes.ClickTarget.tab_bg:
            tabbed_browser.tabopen(url, True)
            return False
        elif target == usertypes.ClickTarget.window:
            from qutebrowser.mainwindow import mainwindow
            window = mainwindow.MainWindow()
            window.show()
            tabbed_browser = objreg.get('tabbed-browser',
                                        scope='window',
                                        window=window.win_id)
            tabbed_browser.tabopen(url, False)
            return False
        else:
            return True
Beispiel #32
0
    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebEnginePage, each time the page wants to create a new
        window of the given type. This might be the result, for example, of a
        JavaScript request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebEnginePage::WebBrowserWindow:
                         A complete web browser window.
                     QWebEnginePage::WebBrowserTab:
                         A web browser tab.
                     QWebEnginePage::WebDialog:
                         A window without decoration.
                     QWebEnginePage::WebBrowserBackgroundTab:
                         A web browser tab without hiding the current visible
                         WebEngineView.

        Return:
            The new QWebEngineView object.
        """
        debug_type = debug.qenum_key(QWebEnginePage, wintype)
        background_tabs = config.get('tabs', 'background-tabs')

        log.webview.debug("createWindow with type {}, background_tabs "
                          "{}".format(debug_type, background_tabs))

        if wintype == QWebEnginePage.WebBrowserWindow:
            # Shift-Alt-Click
            target = usertypes.ClickTarget.window
        elif wintype == QWebEnginePage.WebDialog:
            log.webview.warning("{} requested, but we don't support "
                                "that!".format(debug_type))
            target = usertypes.ClickTarget.tab
        elif wintype == QWebEnginePage.WebBrowserTab:
            # Middle-click / Ctrl-Click with Shift
            # FIXME:qtwebengine this also affects target=_blank links...
            if background_tabs:
                target = usertypes.ClickTarget.tab
            else:
                target = usertypes.ClickTarget.tab_bg
        elif wintype == QWebEnginePage.WebBrowserBackgroundTab:
            # Middle-click / Ctrl-Click
            if background_tabs:
                target = usertypes.ClickTarget.tab_bg
            else:
                target = usertypes.ClickTarget.tab
        else:
            raise ValueError("Invalid wintype {}".format(debug_type))

        tab = shared.get_tab(self._win_id, target)
        return tab._widget  # pylint: disable=protected-access
Beispiel #33
0
    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebEnginePage, each time the page wants to create a new
        window of the given type. This might be the result, for example, of a
        JavaScript request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebEnginePage::WebBrowserWindow:
                         A complete web browser window.
                     QWebEnginePage::WebBrowserTab:
                         A web browser tab.
                     QWebEnginePage::WebDialog:
                         A window without decoration.
                     QWebEnginePage::WebBrowserBackgroundTab:
                         A web browser tab without hiding the current visible
                         WebEngineView. (Added in Qt 5.7)

        Return:
            The new QWebEngineView object.
        """
        debug_type = debug.qenum_key(QWebEnginePage, wintype)
        log.webview.debug("createWindow with type {}".format(debug_type))

        # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-54419
        vercheck = qtutils.version_check
        qtbug_54419_fixed = ((vercheck('5.6.2') and not vercheck('5.7.0'))
                             or qtutils.version_check('5.7.1')
                             or os.environ.get('QUTE_QTBUG54419_PATCHED', ''))
        if not qtbug_54419_fixed:
            log.webview.debug("Ignoring createWindow because of QTBUG-54419")
            return None

        background = False
        if wintype in [
                QWebEnginePage.WebBrowserWindow, QWebEnginePage.WebDialog
        ]:
            log.webview.warning("{} requested, but we don't support "
                                "that!".format(debug_type))
        elif wintype == QWebEnginePage.WebBrowserTab:
            pass
        elif (hasattr(QWebEnginePage, 'WebBrowserBackgroundTab')
              and wintype == QWebEnginePage.WebBrowserBackgroundTab):
            background = True
        else:
            raise ValueError("Invalid wintype {}".format(debug_type))

        tabbed_browser = objreg.get('tabbed-browser',
                                    scope='window',
                                    window=self._win_id)
        # pylint: disable=protected-access
        return tabbed_browser.tabopen(background=background)._widget
Beispiel #34
0
 def __repr__(self):
     # Meh, dependency cycle...
     from qutebrowser.utils.debug import qenum_key
     if self.modifiers is None:
         modifiers = None
     else:
         #modifiers = qflags_key(Qt, self.modifiers)
         modifiers = hex(int(self.modifiers))
     return get_repr(self, constructor=True, key=qenum_key(Qt, self.key),
                     modifiers=modifiers, text=self.text)
Beispiel #35
0
 def __repr__(self):
     # Meh, dependency cycle...
     from qutebrowser.utils.debug import qenum_key
     if self.modifiers is None:
         modifiers = None
     else:
         #modifiers = qflags_key(Qt, self.modifiers)
         modifiers = hex(int(self.modifiers))
     return get_repr(self, constructor=True, key=qenum_key(Qt, self.key),
                     modifiers=modifiers, text=self.text)
Beispiel #36
0
    def acceptNavigationRequest(self, _frame, request, typ):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then opens the URL.

        Args:
            _frame: QWebFrame (target frame)
            request: QNetworkRequest
            typ: QWebPage::NavigationType
        """
        url = request.url()
        urlstr = url.toDisplayString()
        if typ == QWebPage.NavigationTypeReload:
            self.reloading.emit(url)
        if typ != QWebPage.NavigationTypeLinkClicked:
            return True
        if not url.isValid():
            message.error(self._win_id, "Invalid link {} clicked!".format(
                urlstr))
            log.webview.debug(url.errorString())
            self.open_target = usertypes.ClickTarget.normal
            return False
        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        log.webview.debug("acceptNavigationRequest, url {}, type {}, hint "
                          "target {}, open_target {}".format(
                              urlstr, debug.qenum_key(QWebPage, typ),
                              self._hint_target, self.open_target))
        if self._hint_target is not None:
            target = self._hint_target
        else:
            target = self.open_target
        self.open_target = usertypes.ClickTarget.normal
        if target == usertypes.ClickTarget.tab:
            tabbed_browser.tabopen(url, False)
            return False
        elif target == usertypes.ClickTarget.tab_bg:
            tabbed_browser.tabopen(url, True)
            return False
        elif target == usertypes.ClickTarget.window:
            from qutebrowser.mainwindow import mainwindow
            window = mainwindow.MainWindow()
            window.show()
            tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                        window=window.win_id)
            tabbed_browser.tabopen(url, False)
            return False
        else:
            return True
Beispiel #37
0
    def createWindow(self, wintype):
        """Called by Qt when a page wants to create a new window.

        This function is called from the createWindow() method of the
        associated QWebEnginePage, each time the page wants to create a new
        window of the given type. This might be the result, for example, of a
        JavaScript request to open a document in a new window.

        Args:
            wintype: This enum describes the types of window that can be
                     created by the createWindow() function.

                     QWebEnginePage::WebBrowserWindow:
                         A complete web browser window.
                     QWebEnginePage::WebBrowserTab:
                         A web browser tab.
                     QWebEnginePage::WebDialog:
                         A window without decoration.
                     QWebEnginePage::WebBrowserBackgroundTab:
                         A web browser tab without hiding the current visible
                         WebEngineView. (Added in Qt 5.7)

        Return:
            The new QWebEngineView object.
        """
        debug_type = debug.qenum_key(QWebEnginePage, wintype)
        log.webview.debug("createWindow with type {}".format(debug_type))

        # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-54419
        vercheck = qtutils.version_check
        qtbug_54419_fixed = ((vercheck('5.6.2') and not vercheck('5.7.0')) or
                             qtutils.version_check('5.7.1') or
                             os.environ.get('QUTE_QTBUG54419_PATCHED', ''))
        if not qtbug_54419_fixed:
            log.webview.debug("Ignoring createWindow because of QTBUG-54419")
            return None

        background = False
        if wintype in [QWebEnginePage.WebBrowserWindow,
                       QWebEnginePage.WebDialog]:
            log.webview.warning("{} requested, but we don't support "
                                "that!".format(debug_type))
        elif wintype == QWebEnginePage.WebBrowserTab:
            pass
        elif (hasattr(QWebEnginePage, 'WebBrowserBackgroundTab') and
              wintype == QWebEnginePage.WebBrowserBackgroundTab):
            background = True
        else:
            raise ValueError("Invalid wintype {}".format(debug_type))

        tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                    window=self._win_id)
        # pylint: disable=protected-access
        return tabbed_browser.tabopen(background=background)._widget
Beispiel #38
0
def _writable_location(typ):
    """Wrapper around QStandardPaths.writableLocation."""
    with qtutils.unset_organization():
        path = QStandardPaths.writableLocation(typ)
    typ_str = debug.qenum_key(QStandardPaths, typ)
    log.misc.debug("writable location for {}: {}".format(typ_str, path))
    if not path:
        raise EmptyValueError("QStandardPaths returned an empty value!")
    # Qt seems to use '/' as path separator even on Windows...
    path = path.replace('/', os.sep)
    return path
Beispiel #39
0
    def _on_reply_error(self, code):
        """Handle QNetworkReply errors."""
        if code == QNetworkReply.OperationCanceledError:
            return

        if self._reply is None:
            error = "Unknown error: {}".format(
                debug.qenum_key(QNetworkReply, code))
        else:
            error = self._reply.errorString()

        self._die(error)
Beispiel #40
0
    def _on_reply_error(self, code):
        """Handle QNetworkReply errors."""
        if code == QNetworkReply.OperationCanceledError:
            return

        if self._reply is None:
            error = "Unknown error: {}".format(
                debug.qenum_key(QNetworkReply, code))
        else:
            error = self._reply.errorString()

        self._die(error)
Beispiel #41
0
    def interceptRequest(self, info):
        """Handle the given request.

        Reimplementing this virtual function and setting the interceptor on a
        profile makes it possible to intercept URL requests. This function is
        executed on the IO thread, and therefore running long tasks here will
        block networking.

        info contains the information about the URL request and will track
        internally whether its members have been altered.

        Args:
            info: QWebEngineUrlRequestInfo &info
        """
        if 'log-requests' in self._args.debug_flags:
            resource_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                            info.resourceType())
            navigation_type = debug.qenum_key(QWebEngineUrlRequestInfo,
                                              info.navigationType())
            log.webview.debug("{} {}, first-party {}, resource {}, "
                              "navigation {}".format(
                                  bytes(info.requestMethod()).decode('ascii'),
                                  info.requestUrl().toDisplayString(),
                                  info.firstPartyUrl().toDisplayString(),
                                  resource_type, navigation_type))

        url = info.requestUrl()

        # FIXME:qtwebengine only block ads for NavigationTypeOther?
        if self._host_blocker.is_blocked(url):
            log.webview.info("Request to {} blocked by host blocker.".format(
                url.host()))
            info.block(True)

        for header, value in shared.custom_headers(url=url):
            info.setHttpHeader(header, value)

        user_agent = config.instance.get('content.headers.user_agent', url=url)
        if user_agent is not None:
            info.setHttpHeader(b'User-Agent', user_agent.encode('ascii'))
Beispiel #42
0
    def _verify_message(
        self,
        msg: QDBusMessage,
        expected_signature: str,
        expected_type: QDBusMessage.MessageType,
    ) -> None:
        """Check the signature/type of a received message.

        Raises DBusError if the signature doesn't match.
        """
        assert expected_type not in [
            QDBusMessage.ErrorMessage,
            QDBusMessage.InvalidMessage,
        ], expected_type

        if msg.type() == QDBusMessage.ErrorMessage:
            err = msg.errorName()
            if err == "org.freedesktop.DBus.Error.NoReply":
                self.error.emit(
                    msg.errorMessage())  # notification daemon is gone
                return

            raise Error(f"Got DBus error: {err} - {msg.errorMessage()}")

        signature = msg.signature()
        if signature != expected_signature:
            raise Error(
                f"Got a message with signature {signature} but expected "
                f"{expected_signature} (args: {msg.arguments()})")

        typ = msg.type()
        if typ != expected_type:
            type_str = debug.qenum_key(QDBusMessage.MessageType, typ)
            expected_type_str = debug.qenum_key(QDBusMessage.MessageType,
                                                expected_type)
            raise Error(
                f"Got a message of type {type_str} but expected {expected_type_str}"
                f"(args: {msg.arguments()})")
    def retry(self):
        state = self._qt_item.state()
        if state != QWebEngineDownloadItem.DownloadInterrupted:
            log.downloads.warning(
                "Trying to retry download in state {}".format(
                    debug.qenum_key(QWebEngineDownloadItem, state)))
            return

        try:
            self._qt_item.resume()
        except AttributeError:
            raise downloads.UnsupportedOperationError(
                "Retrying downloads is unsupported with QtWebEngine on "
                "Qt/PyQt < 5.10")
Beispiel #44
0
    def retry(self):
        state = self._qt_item.state()
        if state != QWebEngineDownloadItem.DownloadInterrupted:
            log.downloads.warning(
                "Trying to retry download in state {}".format(
                    debug.qenum_key(QWebEngineDownloadItem, state)))
            return

        try:
            self._qt_item.resume()
        except AttributeError:
            raise downloads.UnsupportedOperationError(
                "Retrying downloads is unsupported with QtWebEngine on "
                "Qt/PyQt < 5.10")
Beispiel #45
0
    def acceptNavigationRequest(self,
                                _frame: QWebFrame,
                                request: QNetworkRequest,
                                typ: QWebPage.NavigationType):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then conditionally opens the URL here or in another tab/window.
        """
        url = request.url()
        log.webview.debug("navigation request: url {}, type {}, "
                          "target {} override {}".format(
                              url.toDisplayString(),
                              debug.qenum_key(QWebPage, typ),
                              self.open_target,
                              self._tabdata.override_target))

        if self._tabdata.override_target is not None:
            target = self._tabdata.override_target
            self._tabdata.override_target = None
        else:
            target = self.open_target

        if typ == QWebPage.NavigationTypeReload:
            self.reloading.emit(url)
            return True
        elif typ != QWebPage.NavigationTypeLinkClicked:
            return True

        if not url.isValid():
            msg = urlutils.get_errstring(url, "Invalid link clicked")
            message.error(msg)
            self.open_target = usertypes.ClickTarget.normal
            return False

        if target == usertypes.ClickTarget.normal:
            return True

        tab = shared.get_tab(self._win_id, target)
        tab.openurl(url)
        self.open_target = usertypes.ClickTarget.normal
        return False
Beispiel #46
0
    def acceptNavigationRequest(self,
                                _frame: QWebFrame,
                                request: QNetworkRequest,
                                typ: QWebPage.NavigationType):
        """Override acceptNavigationRequest to handle clicked links.

        Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
        to linkClicked won't work correctly, because when in a frameset, we
        have no idea in which frame the link should be opened.

        Checks if it should open it in a tab (middle-click or control) or not,
        and then conditionally opens the URL here or in another tab/window.
        """
        url = request.url()
        log.webview.debug("navigation request: url {}, type {}, "
                          "target {} override {}".format(
                              url.toDisplayString(),
                              debug.qenum_key(QWebPage, typ),
                              self.open_target,
                              self._tabdata.override_target))

        if self._tabdata.override_target is not None:
            target = self._tabdata.override_target
            self._tabdata.override_target = None
        else:
            target = self.open_target

        if typ == QWebPage.NavigationTypeReload:
            self.reloading.emit(url)
            return True
        elif typ != QWebPage.NavigationTypeLinkClicked:
            return True

        if not url.isValid():
            msg = urlutils.get_errstring(url, "Invalid link clicked")
            message.error(msg)
            self.open_target = usertypes.ClickTarget.normal
            return False

        if target == usertypes.ClickTarget.normal:
            return True

        tab = shared.get_tab(self._win_id, target)
        tab.openurl(url)
        self.open_target = usertypes.ClickTarget.normal
        return False
Beispiel #47
0
    def acceptNavigationRequest(self,
                                url: QUrl,
                                typ: QWebEnginePage.NavigationType,
                                is_main_frame: bool):
        """Override acceptNavigationRequest to handle clicked links.

        This only show an error on invalid links - everything else is handled
        in createWindow.
        """
        log.webview.debug("navigation request: url {}, type {}, is_main_frame "
                          "{}".format(url.toDisplayString(),
                                      debug.qenum_key(QWebEnginePage, typ),
                                      is_main_frame))
        if (typ == QWebEnginePage.NavigationTypeLinkClicked and
                not url.isValid()):
            msg = urlutils.get_errstring(url, "Invalid link clicked")
            message.error(msg)
            return False
        return True
Beispiel #48
0
    def __init__(self, msg, error):
        super().__init__(msg)
        self.error = error

        log.sql.debug("SQL error:")
        log.sql.debug("type: {}".format(
            debug.qenum_key(QSqlError, error.type())))
        log.sql.debug("database text: {}".format(error.databaseText()))
        log.sql.debug("driver text: {}".format(error.driverText()))
        log.sql.debug("error code: {}".format(error.nativeErrorCode()))

        # https://sqlite.org/rescode.html
        # https://github.com/qutebrowser/qutebrowser/issues/2930
        # https://github.com/qutebrowser/qutebrowser/issues/3004
        environmental_errors = [
            '5',   # SQLITE_BUSY ("database is locked")
            '8',   # SQLITE_READONLY
            '13',  # SQLITE_FULL
        ]
        self.environmental = error.nativeErrorCode() in environmental_errors
Beispiel #49
0
def raise_sqlite_error(msg, error):
    """Raise either a BugError or KnownError."""
    error_code = error.nativeErrorCode()
    database_text = error.databaseText()
    driver_text = error.driverText()

    log.sql.debug("SQL error:")
    log.sql.debug("type: {}".format(
        debug.qenum_key(QSqlError, error.type())))
    log.sql.debug("database text: {}".format(database_text))
    log.sql.debug("driver text: {}".format(driver_text))
    log.sql.debug("error code: {}".format(error_code))

    known_errors = [
        SqliteErrorCode.BUSY,
        SqliteErrorCode.READONLY,
        SqliteErrorCode.IOERR,
        SqliteErrorCode.CORRUPT,
        SqliteErrorCode.FULL,
        SqliteErrorCode.CANTOPEN,
    ]

    # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70506
    # We don't know what the actual error was, but let's assume it's not us to
    # blame... Usually this is something like an unreadable database file.
    qtbug_70506 = (error_code == SqliteErrorCode.UNKNOWN and
                   driver_text == "Error opening database" and
                   database_text == "out of memory")

    # https://github.com/qutebrowser/qutebrowser/issues/4681
    # If the query we built was too long
    too_long_err = (
        error_code == SqliteErrorCode.ERROR and
        driver_text == "Unable to execute statement" and
        (database_text.startswith("Expression tree is too large") or
         database_text == "too many SQL variables"))

    if error_code in known_errors or qtbug_70506 or too_long_err:
        raise KnownError(msg, error)

    raise BugError(msg, error)
Beispiel #50
0
    def _on_feature_permission_requested(self, url, feature):
        """Ask the user for approval for geolocation/media/etc.."""
        options = {
            QWebEnginePage.Geolocation: ('content', 'geolocation'),
            QWebEnginePage.MediaAudioCapture: ('content', 'media-capture'),
            QWebEnginePage.MediaVideoCapture: ('content', 'media-capture'),
            QWebEnginePage.MediaAudioVideoCapture:
                ('content', 'media-capture'),
        }
        messages = {
            QWebEnginePage.Geolocation: 'access your location',
            QWebEnginePage.MediaAudioCapture: 'record audio',
            QWebEnginePage.MediaVideoCapture: 'record video',
            QWebEnginePage.MediaAudioVideoCapture: 'record audio/video',
        }
        assert options.keys() == messages.keys()

        if feature not in options:
            log.webview.error("Unhandled feature permission {}".format(
                debug.qenum_key(QWebEnginePage, feature)))
            self.setFeaturePermission(url, feature,
                                      QWebEnginePage.PermissionDeniedByUser)
            return

        yes_action = functools.partial(
            self.setFeaturePermission, url, feature,
            QWebEnginePage.PermissionGrantedByUser)
        no_action = functools.partial(
            self.setFeaturePermission, url, feature,
            QWebEnginePage.PermissionDeniedByUser)

        question = shared.feature_permission(
            url=url, option=options[feature], msg=messages[feature],
            yes_action=yes_action, no_action=no_action,
            abort_on=[self.shutting_down, self.loadStarted])

        if question is not None:
            self.featurePermissionRequestCanceled.connect(
                functools.partial(self._on_feature_permission_cancelled,
                                  question, url, feature))
Beispiel #51
0
 def test_reconverted(self):
     """Test passing a flag value which was re-converted to an enum."""
     # FIXME maybe this should return the right thing anyways?
     debug.qenum_key(Qt, Qt.Alignment(int(Qt.AlignLeft)))
Beispiel #52
0
 def __repr__(self):
     return utils.get_repr(
         self, error=debug.qenum_key(QSslError, self.error()),
         string=self.errorString())
Beispiel #53
0
 def test_int(self):
     """Test passing an int with explicit klass given."""
     key = debug.qenum_key(QFrame, 0x0030, klass=QFrame.Shadow)
     self.assertEqual(key, 'Sunken')
Beispiel #54
0
 def test_unknown(self):
     """Test passing an unknown value."""
     key = debug.qenum_key(QFrame, 0x1337, klass=QFrame.Shadow)
     self.assertEqual(key, '0x1337')
Beispiel #55
0
 def test_qenum_key(self, base, value, klass, expected):
     key = debug.qenum_key(base, value, klass=klass)
     assert key == expected
Beispiel #56
0
 def test_add_base(self):
     key = debug.qenum_key(QFrame, QFrame.Sunken, add_base=True)
     assert key == 'QFrame.Sunken'
Beispiel #57
0
 def test_int_noklass(self):
     """Test passing an int without explicit klass given."""
     with pytest.raises(TypeError):
         debug.qenum_key(QFrame, 42)