Skip to content
Permalink
Browse files
QtWebEngine: Implement custom HTTP headers
  • Loading branch information
The-Compiler committed Sep 7, 2016
1 parent 5a54699 commit 44d1056e5497064b21f7c40f04fa640d8f834ad3
@@ -711,16 +711,12 @@ Valid values:

Default: +pass:[true]+

This setting is only available with the QtWebKit backend.

[[network-accept-language]]
=== accept-language
Value to send in the `accept-language` header.

Default: +pass:[en-US,en]+

This setting is only available with the QtWebKit backend.

[[network-referer-header]]
=== referer-header
Send the Referer header
@@ -804,8 +800,6 @@ Set custom headers for qutebrowser HTTP requests.

Default: empty

This setting is only available with the QtWebKit backend.

== completion
Options related to completion and command history.

@@ -18,3 +18,24 @@
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.

"""Various utilities shared between webpage/webview subclasses."""

from qutebrowser.config import config


def custom_headers():
"""Get the combined custom headers."""
headers = {}
dnt = b'1' if config.get('network', 'do-not-track') else b'0'
headers[b'DNT'] = dnt
headers[b'X-Do-Not-Track'] = dnt

custom_headers = config.get('network', 'custom-headers')
if custom_headers is not None:
for header, value in custom_headers.items():
headers[header.encode('ascii')] = value.encode('ascii')

accept_language = config.get('network', 'accept-language')
if accept_language is not None:
headers[b'Accept-Language'] = accept_language.encode('ascii')

return sorted(headers.items())
@@ -22,6 +22,7 @@
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor

from qutebrowser.browser import shared
from qutebrowser.utils import utils, log


@@ -59,3 +60,6 @@ def interceptRequest(self, info):
log.webview.info("Request to {} blocked by host blocker.".format(
info.requestUrl().host()))
info.block(True)

for header, value in shared.custom_headers():
info.setHttpHeader(header, value)
@@ -31,6 +31,7 @@
from qutebrowser.config import config
from qutebrowser.utils import (message, log, usertypes, utils, objreg, qtutils,
urlutils, debug)
from qutebrowser.browser import shared
from qutebrowser.browser.webkit.network import qutescheme, networkreply
from qutebrowser.browser.webkit.network import filescheme

@@ -449,6 +450,9 @@ def createRequest(self, op, req, outgoing_data):
if result is not None:
return result

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

host_blocker = objreg.get('host-blocker')
if (op == QNetworkAccessManager.GetOperation and
host_blocker.is_blocked(req.url())):
@@ -458,20 +462,6 @@ def createRequest(self, op, req, outgoing_data):
req, HOSTBLOCK_ERROR_STRING, QNetworkReply.ContentAccessDenied,
self)

if config.get('network', 'do-not-track'):
dnt = '1'.encode('ascii')
else:
dnt = '0'.encode('ascii')
req.setRawHeader('DNT'.encode('ascii'), dnt)
req.setRawHeader('X-Do-Not-Track'.encode('ascii'), dnt)

# Load custom headers
custom_headers = config.get('network', 'custom-headers')

if custom_headers is not None:
for header, value in custom_headers.items():
req.setRawHeader(header.encode('ascii'), value.encode('ascii'))

# There are some scenarios where we can't figure out current_url:
# - There's a generic NetworkManager, e.g. for downloads
# - The download was in a tab which is now closed.
@@ -490,10 +480,6 @@ def createRequest(self, op, req, outgoing_data):

self.set_referer(req, current_url)

accept_language = config.get('network', 'accept-language')
if accept_language is not None:
req.setRawHeader('Accept-Language'.encode('ascii'),
accept_language.encode('ascii'))
if PYQT_VERSION < 0x050301:
# WORKAROUND (remove this when we bump the requirements to 5.3.1)
#
@@ -388,13 +388,11 @@ def data(readonly=False):

('network', sect.KeyValue(
('do-not-track',
SettingValue(typ.Bool(), 'true',
backends=[usertypes.Backend.QtWebKit]),
SettingValue(typ.Bool(), 'true'),
"Value to send in the `DNT` header."),

('accept-language',
SettingValue(typ.String(none_ok=True), 'en-US,en',
backends=[usertypes.Backend.QtWebKit]),
SettingValue(typ.String(none_ok=True), 'en-US,en'),
"Value to send in the `accept-language` header."),

('referer-header',
@@ -437,8 +435,7 @@ def data(readonly=False):
"Whether to try to pre-fetch DNS entries to speed up browsing."),

('custom-headers',
SettingValue(typ.HeaderDict(none_ok=True), '',
backends=[usertypes.Backend.QtWebKit]),
SettingValue(typ.HeaderDict(none_ok=True), ''),
"Set custom headers for qutebrowser HTTP requests."),

readonly=readonly
@@ -74,6 +74,8 @@

('tests/unit/browser/test_signalfilter.py',
'qutebrowser/browser/signalfilter.py'),
('tests/unit/browser/test_shared.py',
'qutebrowser/browser/shared.py'),
# ('tests/unit/browser/test_tab.py',
# 'qutebrowser/browser/tab.py'),

@@ -394,12 +394,28 @@ Feature: Various utility commands.

## Custom headers

@qtwebengine_todo: Custom headers are not implemented yet
Scenario: Setting a custom header
When I set network -> custom-headers to {"X-Qute-Test": "testvalue"}
And I open headers
Then the header X-Qute-Test should be set to testvalue

Scenario: DNT header
When I set network -> do-not-track to true
And I open headers
Then the header Dnt should be set to 1
And the header X-Do-Not-Track should be set to 1

Scenario: DNT header (off)
When I set network -> do-not-track to false
And I open headers
Then the header Dnt should be set to 0
And the header X-Do-Not-Track should be set to 0

Scenario: Accept-Language header
When I set network -> accept-language to en,de
And I open headers
Then the header Accept-Language should be set to en,de

## :messages

@qtwebengine_todo: qute:log is not implemented yet
@@ -0,0 +1,51 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:

# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.

import pytest

from qutebrowser.browser import shared


@pytest.mark.parametrize('dnt, accept_language, custom_headers, expected', [
# DNT
(True, None, {}, {b'DNT': b'1', b'X-Do-Not-Track': b'1'}),
(False, None, {}, {b'DNT': b'0', b'X-Do-Not-Track': b'0'}),
# Accept-Language
(False, 'de, en', {}, {b'DNT': b'0', b'X-Do-Not-Track': b'0',
b'Accept-Language': b'de, en'}),
# Custom headers
(False, None, {'X-Qute': 'yes'}, {b'DNT': b'0', b'X-Do-Not-Track': b'0',
b'X-Qute': b'yes'}),
# Mixed
(False, 'de, en', {'X-Qute': 'yes'}, {b'DNT': b'0',
b'X-Do-Not-Track': b'0',
b'Accept-Language': b'de, en',
b'X-Qute': b'yes'}),
])
def test_custom_headers(config_stub, dnt, accept_language, custom_headers,
expected):
config_stub.data = {
'network': {
'do-not-track': dnt,
'accept-language': accept_language,
'custom-headers': custom_headers,
}
}
expected_items = sorted(expected.items())
assert shared.custom_headers() == expected_items

0 comments on commit 44d1056

Please sign in to comment.