Ejemplo n.º 1
0
def test_user_agent(monkeypatch, config_stub, qapp):
    webenginesettings = pytest.importorskip(
        "qutebrowser.browser.webengine.webenginesettings")
    monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine)
    webenginesettings.init_user_agent()

    config_stub.val.content.headers.user_agent = 'test {qt_key}'
    assert websettings.user_agent() == 'test QtWebEngine'

    config_stub.val.content.headers.user_agent = 'test2 {qt_key}'
    assert websettings.user_agent() == 'test2 QtWebEngine'
Ejemplo n.º 2
0
def run_async(tab, cmd, *args, win_id, env, verbose=False,
              output_messages=False):
    """Run a userscript after dumping page html/source.

    Raises:
        UnsupportedError if userscripts are not supported on the current
        platform.
        NotFoundError if the command could not be found.

    Args:
        tab: The WebKitTab/WebEngineTab to get the source from.
        cmd: The userscript binary to run.
        *args: The arguments to pass to the userscript.
        win_id: The window id the userscript is executed in.
        env: A dictionary of variables to add to the process environment.
        verbose: Show notifications when the command started/exited.
        output_messages: Show the output as messages.
    """
    tabbed_browser = objreg.get('tabbed-browser', scope='window',
                                window=win_id)
    commandrunner = runners.CommandRunner(win_id, parent=tabbed_browser)

    if utils.is_posix:
        runner = _POSIXUserscriptRunner(tabbed_browser)
    elif utils.is_windows:  # pragma: no cover
        runner = _WindowsUserscriptRunner(tabbed_browser)
    else:  # pragma: no cover
        raise UnsupportedError

    runner.got_cmd.connect(
        lambda cmd:
        log.commands.debug("Got userscript command: {}".format(cmd)))
    runner.got_cmd.connect(commandrunner.run_safely)

    env['QUTE_USER_AGENT'] = websettings.user_agent()
    env['QUTE_CONFIG_DIR'] = standarddir.config()
    env['QUTE_DATA_DIR'] = standarddir.data()
    env['QUTE_DOWNLOAD_DIR'] = downloads.download_dir()
    env['QUTE_COMMANDLINE_TEXT'] = objreg.get('status-command', scope='window',
                                              window=win_id).text()

    cmd_path = os.path.expanduser(cmd)

    # if cmd is not given as an absolute path, look it up
    # ~/.local/share/qutebrowser/userscripts (or $XDG_DATA_HOME)
    if not os.path.isabs(cmd_path):
        log.misc.debug("{} is no absolute path".format(cmd_path))
        cmd_path = _lookup_path(cmd)
    elif not os.path.exists(cmd_path):
        raise NotFoundError(cmd_path)
    log.misc.debug("Userscript to run: {}".format(cmd_path))

    runner.finished.connect(commandrunner.deleteLater)
    runner.finished.connect(runner.deleteLater)

    runner.prepare_run(cmd_path, *args, env=env, verbose=verbose,
                       output_messages=output_messages)
    tab.dump_async(runner.store_html)
    tab.dump_async(runner.store_text, plain=True)
    return runner
    def set_http_headers(self):
        """Set the user agent and accept-language for the given profile.

        We override those per request in the URL interceptor (to allow for
        per-domain values), but this one still gets used for things like
        window.navigator.userAgent/.languages in JS.
        """
        user_agent = websettings.user_agent()
        self._profile.setHttpUserAgent(user_agent)

        accept_language = config.val.content.headers.accept_language
        if accept_language is not None:
            self._profile.setHttpAcceptLanguage(accept_language)
Ejemplo n.º 4
0
    def get(self, url, **kwargs):
        """Start a download with a link URL.

        Args:
            url: The URL to get, as QUrl
            **kwargs: passed to get_request().

        Return:
            The created DownloadItem.
        """
        if not url.isValid():
            urlutils.invalid_url_error(url, "start download")
            return None

        req = QNetworkRequest(url)
        user_agent = websettings.user_agent(url)
        req.setHeader(QNetworkRequest.UserAgentHeader, user_agent)

        return self.get_request(req, **kwargs)
Ejemplo n.º 5
0
    def get(self, url, cache=True, **kwargs):
        """Start a download with a link URL.

        Args:
            url: The URL to get, as QUrl
            cache: If set to False, don't cache the response.
            **kwargs: passed to get_request().

        Return:
            The created DownloadItem.
        """
        if not url.isValid():
            urlutils.invalid_url_error(url, "start download")
            return None

        req = QNetworkRequest(url)
        user_agent = websettings.user_agent(url)
        req.setHeader(QNetworkRequest.UserAgentHeader, user_agent)

        if not cache:
            req.setAttribute(QNetworkRequest.CacheSaveControlAttribute, False)

        return self.get_request(req, **kwargs)
Ejemplo n.º 6
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.

        On Qt < 5.13, 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 objects.debug_flags:
            resource_type_str = debug.qenum_key(QWebEngineUrlRequestInfo,
                                                info.resourceType())
            navigation_type_str = debug.qenum_key(QWebEngineUrlRequestInfo,
                                                  info.navigationType())
            log.network.debug("{} {}, first-party {}, resource {}, "
                              "navigation {}".format(
                                  bytes(info.requestMethod()).decode('ascii'),
                                  info.requestUrl().toDisplayString(),
                                  info.firstPartyUrl().toDisplayString(),
                                  resource_type_str, navigation_type_str))

        url = info.requestUrl()
        first_party = info.firstPartyUrl()
        if not url.isValid():
            log.network.debug("Ignoring invalid intercepted URL: {}".format(
                url.errorString()))
            return

        # Per QWebEngineUrlRequestInfo::ResourceType documentation, if we fail
        # our lookup, we should fall back to ResourceTypeUnknown
        try:
            resource_type = self._resource_types[info.resourceType()]
        except KeyError:
            log.network.warning(
                "Resource type {} not found in RequestInterceptor dict."
                .format(debug.qenum_key(QWebEngineUrlRequestInfo,
                                        info.resourceType())))
            resource_type = interceptors.ResourceType.unknown

        is_xhr = info.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeXhr

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

        # FIXME:qtwebengine only block ads for NavigationTypeOther?
        request = WebEngineRequest(
            first_party_url=first_party,
            request_url=url,
            resource_type=resource_type,
            webengine_info=info)

        interceptors.run(request)
        if request.is_blocked:
            info.block(True)

        for header, value in shared.custom_headers(url=url):
            if header.lower() == b'accept' and is_xhr:
                # https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader
                # says: "If no Accept header has been set using this, an Accept header
                # with the type "*/*" is sent with the request when send() is called."
                #
                # We shouldn't break that if someone sets a custom Accept header for
                # normal requests.
                continue
            info.setHttpHeader(header, value)

        # Note this is ignored before Qt 5.12.4 and 5.13.1 due to
        # https://bugreports.qt.io/browse/QTBUG-60203 - there, we set the
        # commandline-flag in qtargs.py instead.
        if config.cache['content.headers.referer'] == 'never':
            info.setHttpHeader(b'Referer', b'')

        user_agent = websettings.user_agent(url)
        info.setHttpHeader(b'User-Agent', user_agent.encode('ascii'))
Ejemplo n.º 7
0
 def userAgentForUrl(self, url):
     """Override QWebPage::userAgentForUrl to customize the user agent."""
     if not url.isValid():
         url = None
     return websettings.user_agent(url)
Ejemplo n.º 8
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.

        On Qt < 5.13, 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 objects.debug_flags:
            resource_type_str = debug.qenum_key(QWebEngineUrlRequestInfo,
                                                info.resourceType())
            navigation_type_str = 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_str, navigation_type_str))

        url = info.requestUrl()
        first_party = info.firstPartyUrl()
        if not url.isValid():
            log.webview.debug("Ignoring invalid intercepted URL: {}".format(
                url.errorString()))
            return

        # Per QWebEngineUrlRequestInfo::ResourceType documentation, if we fail
        # our lookup, we should fall back to ResourceTypeUnknown
        try:
            resource_type = self._resource_types[info.resourceType()]
        except KeyError:
            log.webview.warning(
                "Resource type {} not found in RequestInterceptor dict.".
                format(
                    debug.qenum_key(QWebEngineUrlRequestInfo,
                                    info.resourceType())))
            resource_type = interceptors.ResourceType.unknown

        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 = WebEngineRequest(first_party_url=first_party,
                                   request_url=url,
                                   resource_type=resource_type,
                                   webengine_info=info)

        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 = websettings.user_agent(url)
        info.setHttpHeader(b'User-Agent', user_agent.encode('ascii'))
Ejemplo n.º 9
0
 def userAgentForUrl(self, url):
     """Override QWebPage::userAgentForUrl to customize the user agent."""
     return websettings.user_agent(url)