Implement a HeaderDict config type

Supersedes #1132.
Fixes #1022.
This commit is contained in:
Florian Bruhin 2016-04-15 20:37:26 +02:00
parent d33fae455d
commit c5999443a1
2 changed files with 91 additions and 0 deletions

View File

@ -20,6 +20,7 @@
"""Setting options used for qutebrowser."""
import re
import json
import shlex
import base64
import codecs
@ -1423,6 +1424,61 @@ class UrlList(List):
"{}".format(val.errorString()))
class HeaderDict(BaseType):
"""A JSON-like dictionary for custom HTTP headers."""
def validate(self, value):
self._basic_validation(value)
if not value:
return
try:
json_val = json.loads(value)
except ValueError as e:
raise configexc.ValidationError(value, str(e))
if not isinstance(json_val, dict):
raise configexc.ValidationError(value, "Expected json dict, but "
"got {}".format(type(json_val)))
if not json_val:
if self.none_ok:
return
else:
raise configexc.ValidationError(value, "may not be empty!")
for key, val in json_val.items():
if not isinstance(key, str):
msg = "Expected string for key {!r} but got {}".format(
key, type(key))
raise configexc.ValidationError(value, msg)
if not isinstance(val, str):
msg = "Expected string for value {!r} but got {}".format(
key, type(key))
raise configexc.ValidationError(value, msg)
try:
key.encode('ascii')
except UnicodeEncodeError as e:
msg = "Key {!r} contains non-ascii characters: {}".format(
key, e)
raise configexc.ValidationError(value, msg)
try:
val.encode('ascii')
except UnicodeEncodeError as e:
msg = "Value {!r} contains non-ascii characters: {}".format(
val, e)
raise configexc.ValidationError(value, msg)
def transform(self, value):
val = json.loads(value)
return val or None
class SessionName(BaseType):
"""The name of a session."""

View File

@ -1715,6 +1715,41 @@ class TestSearchEngineName:
assert klass().transform(val) == expected
class TestHeaderDict:
@pytest.fixture
def klass(self):
return configtypes.HeaderDict
@pytest.mark.parametrize('val', [
'{"foo": "bar"}',
'{"foo": "bar", "baz": "fish"}',
'', # empty value with none_ok=true
'{}', # ditto
])
def test_validate_valid(self, klass, val):
klass(none_ok=True).validate(val)
@pytest.mark.parametrize('val', [
'["foo"]', # valid json but not a dict
'{"hello": 23}', # non-string as value
'{"hällo": "world"}', # non-ascii data in key
'{"hello": "wörld"}', # non-ascii data in value
'', # empty value with none_ok=False
'{}', # ditto
])
def test_validate_invalid(self, klass, val):
with pytest.raises(configexc.ValidationError):
klass().validate(val)
@pytest.mark.parametrize('val, expected', [
('{"foo": "bar"}', {"foo": "bar"}),
('{}', None),
])
def test_transform(self, klass, val, expected):
assert klass(none_ok=True).transform(val) == expected
class TestSearchEngineUrl:
"""Test SearchEngineUrl."""