171 lines
6.4 KiB
Python
171 lines
6.4 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""
|
||
|
h2/config
|
||
|
~~~~~~~~~
|
||
|
|
||
|
Objects for controlling the configuration of the HTTP/2 stack.
|
||
|
"""
|
||
|
|
||
|
|
||
|
class _BooleanConfigOption:
|
||
|
"""
|
||
|
Descriptor for handling a boolean config option. This will block
|
||
|
attempts to set boolean config options to non-bools.
|
||
|
"""
|
||
|
def __init__(self, name):
|
||
|
self.name = name
|
||
|
self.attr_name = '_%s' % self.name
|
||
|
|
||
|
def __get__(self, instance, owner):
|
||
|
return getattr(instance, self.attr_name)
|
||
|
|
||
|
def __set__(self, instance, value):
|
||
|
if not isinstance(value, bool):
|
||
|
raise ValueError("%s must be a bool" % self.name)
|
||
|
setattr(instance, self.attr_name, value)
|
||
|
|
||
|
|
||
|
class DummyLogger:
|
||
|
"""
|
||
|
An Logger object that does not actual logging, hence a DummyLogger.
|
||
|
|
||
|
For the class the log operation is merely a no-op. The intent is to avoid
|
||
|
conditionals being sprinkled throughout the hyper-h2 code for calls to
|
||
|
logging functions when no logger is passed into the corresponding object.
|
||
|
"""
|
||
|
def __init__(self, *vargs):
|
||
|
pass
|
||
|
|
||
|
def debug(self, *vargs, **kwargs):
|
||
|
"""
|
||
|
No-op logging. Only level needed for now.
|
||
|
"""
|
||
|
pass
|
||
|
|
||
|
def trace(self, *vargs, **kwargs):
|
||
|
"""
|
||
|
No-op logging. Only level needed for now.
|
||
|
"""
|
||
|
pass
|
||
|
|
||
|
|
||
|
class H2Configuration:
|
||
|
"""
|
||
|
An object that controls the way a single HTTP/2 connection behaves.
|
||
|
|
||
|
This object allows the users to customize behaviour. In particular, it
|
||
|
allows users to enable or disable optional features, or to otherwise handle
|
||
|
various unusual behaviours.
|
||
|
|
||
|
This object has very little behaviour of its own: it mostly just ensures
|
||
|
that configuration is self-consistent.
|
||
|
|
||
|
:param client_side: Whether this object is to be used on the client side of
|
||
|
a connection, or on the server side. Affects the logic used by the
|
||
|
state machine, the default settings values, the allowable stream IDs,
|
||
|
and several other properties. Defaults to ``True``.
|
||
|
:type client_side: ``bool``
|
||
|
|
||
|
:param header_encoding: Controls whether the headers emitted by this object
|
||
|
in events are transparently decoded to ``unicode`` strings, and what
|
||
|
encoding is used to do that decoding. This defaults to ``None``,
|
||
|
meaning that headers will be returned as bytes. To automatically
|
||
|
decode headers (that is, to return them as unicode strings), this can
|
||
|
be set to the string name of any encoding, e.g. ``'utf-8'``.
|
||
|
|
||
|
.. versionchanged:: 3.0.0
|
||
|
Changed default value from ``'utf-8'`` to ``None``
|
||
|
|
||
|
:type header_encoding: ``str``, ``False``, or ``None``
|
||
|
|
||
|
:param validate_outbound_headers: Controls whether the headers emitted
|
||
|
by this object are validated against the rules in RFC 7540.
|
||
|
Disabling this setting will cause outbound header validation to
|
||
|
be skipped, and allow the object to emit headers that may be illegal
|
||
|
according to RFC 7540. Defaults to ``True``.
|
||
|
:type validate_outbound_headers: ``bool``
|
||
|
|
||
|
:param normalize_outbound_headers: Controls whether the headers emitted
|
||
|
by this object are normalized before sending. Disabling this setting
|
||
|
will cause outbound header normalization to be skipped, and allow
|
||
|
the object to emit headers that may be illegal according to
|
||
|
RFC 7540. Defaults to ``True``.
|
||
|
:type normalize_outbound_headers: ``bool``
|
||
|
|
||
|
:param validate_inbound_headers: Controls whether the headers received
|
||
|
by this object are validated against the rules in RFC 7540.
|
||
|
Disabling this setting will cause inbound header validation to
|
||
|
be skipped, and allow the object to receive headers that may be illegal
|
||
|
according to RFC 7540. Defaults to ``True``.
|
||
|
:type validate_inbound_headers: ``bool``
|
||
|
|
||
|
:param normalize_inbound_headers: Controls whether the headers received by
|
||
|
this object are normalized according to the rules of RFC 7540.
|
||
|
Disabling this setting may lead to hyper-h2 emitting header blocks that
|
||
|
some RFCs forbid, e.g. with multiple cookie fields.
|
||
|
|
||
|
.. versionadded:: 3.0.0
|
||
|
|
||
|
:type normalize_inbound_headers: ``bool``
|
||
|
|
||
|
:param logger: A logger that conforms to the requirements for this module,
|
||
|
those being no I/O and no context switches, which is needed in order
|
||
|
to run in asynchronous operation.
|
||
|
|
||
|
.. versionadded:: 2.6.0
|
||
|
|
||
|
:type logger: ``logging.Logger``
|
||
|
"""
|
||
|
client_side = _BooleanConfigOption('client_side')
|
||
|
validate_outbound_headers = _BooleanConfigOption(
|
||
|
'validate_outbound_headers'
|
||
|
)
|
||
|
normalize_outbound_headers = _BooleanConfigOption(
|
||
|
'normalize_outbound_headers'
|
||
|
)
|
||
|
validate_inbound_headers = _BooleanConfigOption(
|
||
|
'validate_inbound_headers'
|
||
|
)
|
||
|
normalize_inbound_headers = _BooleanConfigOption(
|
||
|
'normalize_inbound_headers'
|
||
|
)
|
||
|
|
||
|
def __init__(self,
|
||
|
client_side=True,
|
||
|
header_encoding=None,
|
||
|
validate_outbound_headers=True,
|
||
|
normalize_outbound_headers=True,
|
||
|
validate_inbound_headers=True,
|
||
|
normalize_inbound_headers=True,
|
||
|
logger=None):
|
||
|
self.client_side = client_side
|
||
|
self.header_encoding = header_encoding
|
||
|
self.validate_outbound_headers = validate_outbound_headers
|
||
|
self.normalize_outbound_headers = normalize_outbound_headers
|
||
|
self.validate_inbound_headers = validate_inbound_headers
|
||
|
self.normalize_inbound_headers = normalize_inbound_headers
|
||
|
self.logger = logger or DummyLogger(__name__)
|
||
|
|
||
|
@property
|
||
|
def header_encoding(self):
|
||
|
"""
|
||
|
Controls whether the headers emitted by this object in events are
|
||
|
transparently decoded to ``unicode`` strings, and what encoding is used
|
||
|
to do that decoding. This defaults to ``None``, meaning that headers
|
||
|
will be returned as bytes. To automatically decode headers (that is, to
|
||
|
return them as unicode strings), this can be set to the string name of
|
||
|
any encoding, e.g. ``'utf-8'``.
|
||
|
"""
|
||
|
return self._header_encoding
|
||
|
|
||
|
@header_encoding.setter
|
||
|
def header_encoding(self, value):
|
||
|
"""
|
||
|
Enforces constraints on the value of header encoding.
|
||
|
"""
|
||
|
if not isinstance(value, (bool, str, type(None))):
|
||
|
raise ValueError("header_encoding must be bool, string, or None")
|
||
|
if value is True:
|
||
|
raise ValueError("header_encoding cannot be True")
|
||
|
self._header_encoding = value
|