Hello community,
here is the log from the commit of package python-h2 for openSUSE:Factory checked in at 2019-03-29 20:38:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-h2 (Old)
and /work/SRC/openSUSE:Factory/.python-h2.new.25356 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-h2"
Fri Mar 29 20:38:42 2019 rev:3 rq:689263 version:3.1.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-h2/python-h2.changes 2018-12-27 00:26:27.347807172 +0100
+++ /work/SRC/openSUSE:Factory/.python-h2.new.25356/python-h2.changes 2019-03-29 20:38:43.850680088 +0100
@@ -1,0 +2,25 @@
+Thu Mar 28 04:06:48 UTC 2019 - John Vandenberg
+
+- Set URL to more useful https://github.com/python-hyper/hyper-h2
+- Update to v3.1.0
+ * API Changes (Backward-Incompatible)
+ + h2.connection.H2Connection.data_to_send first and only
+ argument ``amt`` was renamed to ``amount``
+ + Support for Python 3.3 has been removed.
+ * API Changes (Backward-Compatible)
+ + h2.connection.H2Connection.send_data now supports ``data``
+ parameter being a ``memoryview`` object.
+ + Refactor ping-related events: a h2.events.PingReceived event is
+ fired when a PING frame is received and a h2.events.PingAckReceived
+ event is fired when a PING frame with an ACK flag is received
+ + h2.events.PingAcknowledged is deprecated in favour of the
+ identical h2.events.PingAckReceived
+ + Added ENABLE_CONNECT_PROTOCOL to h2.settings.SettingCodes
+ + Support CONNECT requests with a ``:protocol`` pseudo header
+ thereby supporting RFC 8441.
+ + A limit to the number of closed streams kept in memory by the
+ connection is applied. It can be configured by
+ h2.connection.H2Connection.MAX_CLOSED_STREAMS
+ * Debug logging when stream_id is None is now fixed and no longer errors.
+
+-------------------------------------------------------------------
Old:
----
h2-3.0.1.tar.gz
New:
----
h2-3.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-h2.spec ++++++
--- /var/tmp/diff_new_pack.0WqcQq/_old 2019-03-29 20:38:44.462680400 +0100
+++ /var/tmp/diff_new_pack.0WqcQq/_new 2019-03-29 20:38:44.470680404 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-h2
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,25 +18,25 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-h2
-Version: 3.0.1
+Version: 3.1.0
Release: 0
Summary: HTTP/2 State-Machine based protocol implementation
License: MIT
Group: Development/Languages/Python
-URL: http://hyper.rtfd.org
+URL: https://github.com/python-hyper/hyper-h2
Source0: https://files.pythonhosted.org/packages/source/h/h2/h2-%{version}.tar.gz
# test requirements
BuildRequires: %{python_module coverage}
-BuildRequires: %{python_module hpack}
-BuildRequires: %{python_module hyperframe >= 5.0}
+BuildRequires: %{python_module hpack >= 2.3}
+BuildRequires: %{python_module hyperframe >= 5.2.0}
BuildRequires: %{python_module hypothesis}
BuildRequires: %{python_module pytest-cov}
BuildRequires: %{python_module pytest-xdist}
BuildRequires: %{python_module pytest}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Requires: python-hpack >= 2.2
-Requires: python-hyperframe >= 5.0
+Requires: python-hpack >= 2.3
+Requires: python-hyperframe >= 5.2.0
BuildArch: noarch
%python_subpackages
++++++ h2-3.0.1.tar.gz -> h2-3.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/CONTRIBUTORS.rst new/h2-3.1.0/CONTRIBUTORS.rst
--- old/h2-3.0.1/CONTRIBUTORS.rst 2017-04-03 09:47:32.000000000 +0200
+++ new/h2-3.1.0/CONTRIBUTORS.rst 2019-01-22 18:41:43.000000000 +0100
@@ -111,4 +111,5 @@
- Fred Thomsen (@fredthomsen)
- Added logging.
-
+ - Enhance equality testing of ``h2.settings.Settings`` objects with
+ ``hypothesis``.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/HISTORY.rst new/h2-3.1.0/HISTORY.rst
--- old/h2-3.0.1/HISTORY.rst 2017-04-03 09:58:48.000000000 +0200
+++ new/h2-3.1.0/HISTORY.rst 2019-01-22 18:41:49.000000000 +0100
@@ -1,6 +1,38 @@
Release History
===============
+3.1.0 (2019-01-22)
+------------------
+
+API Changes (Backward-Incompatible)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``h2.connection.H2Connection.data_to_send`` first and only argument ``amt``
+ was renamed to ``amount``.
+- Support for Python 3.3 has been removed.
+
+API Changes (Backward-Compatible)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``h2.connection.H2Connection.send_data`` now supports ``data`` parameter
+ being a ``memoryview`` object.
+- Refactor ping-related events: a ``h2.events.PingReceived`` event is fired
+ when a PING frame is received and a ``h2.events.PingAckReceived`` event is
+ fired when a PING frame with an ACK flag is received.
+ ``h2.events.PingAcknowledged`` is deprecated in favour of the identical
+ ``h2.events.PingAckReceived``.
+- Added ``ENABLE_CONNECT_PROTOCOL`` to ``h2.settings.SettingCodes``.
+- Support ``CONNECT`` requests with a ``:protocol`` pseudo header
+ thereby supporting RFC 8441.
+- A limit to the number of closed streams kept in memory by the
+ connection is applied. It can be configured by
+ ``h2.connection.H2Connection.MAX_CLOSED_STREAMS``.
+
+Bugfixes
+~~~~~~~~
+
+- Debug logging when stream_id is None is now fixed and no longer errors.
+
3.0.1 (2017-04-03)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/PKG-INFO new/h2-3.1.0/PKG-INFO
--- old/h2-3.0.1/PKG-INFO 2017-04-03 10:07:26.000000000 +0200
+++ new/h2-3.1.0/PKG-INFO 2019-01-22 18:42:26.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: h2
-Version: 3.0.1
+Version: 3.1.0
Summary: HTTP/2 State-Machine based protocol implementation
Home-page: http://hyper.rtfd.org
Author: Cory Benfield
@@ -76,6 +76,38 @@
Release History
===============
+ 3.1.0 (2019-01-22)
+ ------------------
+
+ API Changes (Backward-Incompatible)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - ``h2.connection.H2Connection.data_to_send`` first and only argument ``amt``
+ was renamed to ``amount``.
+ - Support for Python 3.3 has been removed.
+
+ API Changes (Backward-Compatible)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - ``h2.connection.H2Connection.send_data`` now supports ``data`` parameter
+ being a ``memoryview`` object.
+ - Refactor ping-related events: a ``h2.events.PingReceived`` event is fired
+ when a PING frame is received and a ``h2.events.PingAckReceived`` event is
+ fired when a PING frame with an ACK flag is received.
+ ``h2.events.PingAcknowledged`` is deprecated in favour of the identical
+ ``h2.events.PingAckReceived``.
+ - Added ``ENABLE_CONNECT_PROTOCOL`` to ``h2.settings.SettingCodes``.
+ - Support ``CONNECT`` requests with a ``:protocol`` pseudo header
+ thereby supporting RFC 8441.
+ - A limit to the number of closed streams kept in memory by the
+ connection is applied. It can be configured by
+ ``h2.connection.H2Connection.MAX_CLOSED_STREAMS``.
+
+ Bugfixes
+ ~~~~~~~~
+
+ - Debug logging when stream_id is None is now fixed and no longer errors.
+
3.0.1 (2017-04-03)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/docs/source/api.rst new/h2-3.1.0/docs/source/api.rst
--- old/h2-3.0.1/docs/source/api.rst 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/docs/source/api.rst 2019-01-22 18:41:43.000000000 +0100
@@ -53,7 +53,10 @@
.. autoclass:: h2.events.RemoteSettingsChanged
:members:
-.. autoclass:: h2.events.PingAcknowledged
+.. autoclass:: h2.events.PingReceived
+ :members:
+
+.. autoclass:: h2.events.PingAckReceived
:members:
.. autoclass:: h2.events.StreamEnded
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/docs/source/basic-usage.rst new/h2-3.1.0/docs/source/basic-usage.rst
--- old/h2-3.0.1/docs/source/basic-usage.rst 2017-03-16 10:02:02.000000000 +0100
+++ new/h2-3.1.0/docs/source/basic-usage.rst 2019-01-22 18:41:43.000000000 +0100
@@ -251,9 +251,11 @@
.. code-block:: python
import h2.connection
+ import h2.config
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
while True:
data = sock.recv(65535)
@@ -267,9 +269,11 @@
import socket
import h2.connection
+ import h2.config
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
while True:
data = sock.recv(65535)
@@ -331,7 +335,8 @@
.. code-block:: python
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
sock.sendall(conn.data_to_send())
@@ -359,9 +364,11 @@
import socket
import h2.connection
+ import h2.config
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
sock.sendall(conn.data_to_send())
@@ -493,9 +500,11 @@
.. code-block:: python
import h2.events
+ import h2.config
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
sock.sendall(conn.data_to_send())
@@ -528,6 +537,7 @@
import h2.connection
import h2.events
+ import h2.config
def send_response(conn, event):
stream_id = event.stream_id
@@ -545,7 +555,8 @@
)
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
sock.sendall(conn.data_to_send())
@@ -633,6 +644,7 @@
import h2.connection
import h2.events
+ import h2.config
def send_response(conn, event):
stream_id = event.stream_id
@@ -654,7 +666,8 @@
)
def handle(sock):
- conn = h2.connection.H2Connection(client_side=False)
+ config = h2.config.H2Configuration(client_side=False)
+ conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
sock.sendall(conn.data_to_send())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/docs/source/conf.py new/h2-3.1.0/docs/source/conf.py
--- old/h2-3.0.1/docs/source/conf.py 2017-04-03 09:58:57.000000000 +0200
+++ new/h2-3.1.0/docs/source/conf.py 2019-01-22 18:41:49.000000000 +0100
@@ -55,9 +55,9 @@
# built documents.
#
# The short X.Y version.
-version = '3.0.1'
+version = '3.1.0'
# The full version, including alpha/beta/rc tags.
-release = '3.0.1'
+release = '3.1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/docs/source/negotiating-http2.rst new/h2-3.1.0/docs/source/negotiating-http2.rst
--- old/h2-3.0.1/docs/source/negotiating-http2.rst 2017-04-03 09:47:32.000000000 +0200
+++ new/h2-3.1.0/docs/source/negotiating-http2.rst 2019-01-22 18:41:43.000000000 +0100
@@ -5,15 +5,19 @@
.. _starting-alpn:
-HTTPS URLs (ALPN and NPN)
+HTTPS URLs (ALPN)
-------------------------
-Starting HTTP/2 for HTTPS URLs is outlined in `RFC 7540 Section 3.3`_. In this case, the client and server use a TLS extension to negotiate HTTP/2: typically either or both of `NPN`_ or `ALPN`_. How to use NPN and ALPN is currently not covered in this document: please consult the documentation for either the :mod:`ssl module python:ssl` in the standard library, or the :mod:`PyOpenSSL pyopenssl:OpenSSL.SSL` third-party modules, for more on this topic.
+Starting HTTP/2 for HTTPS URLs is outlined in `RFC 7540 Section 3.3`_. In this case, the client and server use a TLS extension to negotiate HTTP/2: `ALPN`_. How to use ALPN is currently not covered in this document: please consult the documentation for either the :mod:`ssl module python:ssl` in the standard library, or the :mod:`PyOpenSSL pyopenssl:OpenSSL.SSL` third-party modules, for more on this topic.
This method is the simplest to use once the TLS connection is established. To use it with Hyper-h2, after you've established the connection and confirmed that HTTP/2 has been negotiated with `ALPN`_, create a :class:`H2Connection ` object and call :meth:`H2Connection.initiate_connection `. This will ensure that the appropriate preamble data is placed in the data buffer. You should then immediately send the data returned by :meth:`H2Connection.data_to_send ` on your TLS connection.
At this point, you're free to use all the HTTP/2 functionality provided by Hyper-h2.
+.. note::
+ Although Hyper-h2 is not concerned with negotiating protocol versions, it is important to note that support for `ALPN`_ is not available in the standard library of Python versions < 2.7.9.
+ As a consequence, clients may encounter various errors due to protocol versions mismatch.
+
Server Setup Example
~~~~~~~~~~~~~~~~~~~~
@@ -90,11 +94,10 @@
Prior Knowledge
---------------
-It's possible that you as a client know that a particular server supports HTTP/2, and that you do not need to perform any of the negotiations described above. In that case, you may follow the steps in :ref:`starting-alpn`, ignoring all references to ALPN and NPN: there's no need to perform the upgrade dance described in :ref:`starting-upgrade`.
+It's possible that you as a client know that a particular server supports HTTP/2, and that you do not need to perform any of the negotiations described above. In that case, you may follow the steps in :ref:`starting-alpn`, ignoring all references to ALPN: there's no need to perform the upgrade dance described in :ref:`starting-upgrade`.
.. _RFC 7540: https://tools.ietf.org/html/rfc7540
.. _RFC 7540 Section 3.2: https://tools.ietf.org/html/rfc7540#section-3.2
.. _RFC 7540 Section 3.3: https://tools.ietf.org/html/rfc7540#section-3.3
-.. _NPN: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
.. _ALPN: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
.. _RFC 7230 Section 6.7: https://tools.ietf.org/html/rfc7230#section-6.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/examples/curio/curio-server.py new/h2-3.1.0/examples/curio/curio-server.py
--- old/h2-3.0.1/examples/curio/curio-server.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/examples/curio/curio-server.py 2019-01-22 18:41:43.000000000 +0100
@@ -12,7 +12,7 @@
import os
import sys
-from curio import Kernel, Event, spawn, socket, ssl
+from curio import Event, spawn, socket, ssl, run
import h2.config
import h2.connection
@@ -23,7 +23,7 @@
READ_CHUNK_SIZE = 8192
-def create_listening_ssl_socket(address, certfile, keyfile):
+async def create_listening_ssl_socket(address, certfile, keyfile):
"""
Create and return a listening TLS socket on a given address.
"""
@@ -37,7 +37,7 @@
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock = ssl_context.wrap_socket(sock)
+ sock = await ssl_context.wrap_socket(sock)
sock.bind(address)
sock.listen()
@@ -48,7 +48,7 @@
"""
Create an HTTP/2 server at the given address.
"""
- sock = create_listening_ssl_socket(address, certfile, keyfile)
+ sock = await create_listening_ssl_socket(address, certfile, keyfile)
print("Now listening on %s:%d" % address)
async with sock:
@@ -196,13 +196,11 @@
if __name__ == '__main__':
host = sys.argv[2] if len(sys.argv) > 2 else "localhost"
- kernel = Kernel(with_monitor=True)
print("Try GETting:")
print(" On OSX after 'brew install curl --with-c-ares --with-libidn --with-nghttp2 --with-openssl':")
print("/usr/local/opt/curl/bin/curl --tlsv1.2 --http2 -k https://localhost:5000/bundle.js")
print("Or open a browser to: https://localhost:5000/")
print(" (Accept all the warnings)")
- kernel.run(h2_server((host, 5000),
- sys.argv[1],
- "{}.crt.pem".format(host),
- "{}.key".format(host)))
+ run(h2_server((host, 5000), sys.argv[1],
+ "{}.crt.pem".format(host),
+ "{}.key".format(host)), with_monitor=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/examples/eventlet/eventlet-server.py new/h2-3.1.0/examples/eventlet/eventlet-server.py
--- old/h2-3.0.1/examples/eventlet/eventlet-server.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/examples/eventlet/eventlet-server.py 2019-01-22 18:41:43.000000000 +0100
@@ -51,7 +51,7 @@
response_headers = (
(':status', '200'),
('content-type', 'application/json'),
- ('content-length', len(data)),
+ ('content-length', str(len(data))),
('server', 'eventlet-h2'),
)
self.conn.send_headers(stream_id, response_headers)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/examples/fragments/client_upgrade_fragment.py new/h2-3.1.0/examples/fragments/client_upgrade_fragment.py
--- old/h2-3.0.1/examples/fragments/client_upgrade_fragment.py 2017-03-16 10:02:02.000000000 +0100
+++ new/h2-3.1.0/examples/fragments/client_upgrade_fragment.py 2019-01-22 18:41:43.000000000 +0100
@@ -38,7 +38,7 @@
b"GET / HTTP/1.1\r\n" +
b"Host: localhost\r\n" +
b"Upgrade: h2c\r\n" +
- b"HTTP2-Settings: " + settings + "\r\n"
+ b"HTTP2-Settings: " + settings + b"\r\n" +
b"\r\n"
)
connection.sendall(request)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/examples/fragments/server_upgrade_fragment.py new/h2-3.1.0/examples/fragments/server_upgrade_fragment.py
--- old/h2-3.0.1/examples/fragments/server_upgrade_fragment.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/examples/fragments/server_upgrade_fragment.py 2019-01-22 18:41:43.000000000 +0100
@@ -45,14 +45,14 @@
data += connection.recv(8192)
match = re.search(b'Upgrade: h2c\r\n', data)
- if match is not None:
+ if match is None:
raise RuntimeError("HTTP/2 upgrade not requested!")
# We need to look for the HTTP2-Settings header field. Again, in production
# code you shouldn't use regular expressions for this, but it's good enough
# for the example.
match = re.search(b'HTTP2-Settings: (\\S+)\r\n', data)
- if match is not None:
+ if match is None:
raise RuntimeError("HTTP2-Settings header field not present!")
return match.group(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/__init__.py new/h2-3.1.0/h2/__init__.py
--- old/h2-3.0.1/h2/__init__.py 2017-04-03 09:58:51.000000000 +0200
+++ new/h2-3.1.0/h2/__init__.py 2019-01-22 18:41:49.000000000 +0100
@@ -5,4 +5,4 @@
A HTTP/2 implementation.
"""
-__version__ = '3.0.1'
+__version__ = '3.1.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/connection.py new/h2-3.1.0/h2/connection.py
--- old/h2-3.0.1/h2/connection.py 2017-04-03 09:57:49.000000000 +0200
+++ new/h2-3.1.0/h2/connection.py 2019-01-22 18:41:43.000000000 +0100
@@ -21,7 +21,7 @@
from .config import H2Configuration
from .errors import ErrorCodes, _error_code_from_int
from .events import (
- WindowUpdated, RemoteSettingsChanged, PingAcknowledged,
+ WindowUpdated, RemoteSettingsChanged, PingReceived, PingAckReceived,
SettingsAcknowledged, ConnectionTerminated, PriorityUpdated,
AlternativeServiceAvailable, UnknownFrameReceived
)
@@ -33,7 +33,7 @@
from .frame_buffer import FrameBuffer
from .settings import Settings, SettingCodes
from .stream import H2Stream, StreamClosedBy
-from .utilities import guard_increment_window
+from .utilities import SizeLimitDict, guard_increment_window
from .windows import WindowManager
@@ -281,6 +281,9 @@
# The initial default value of SETTINGS_MAX_HEADER_LIST_SIZE.
DEFAULT_MAX_HEADER_LIST_SIZE = 2**16
+ # Keep in memory limited amount of results for streams closes
+ MAX_CLOSED_STREAMS = 2**16
+
def __init__(self, config=None):
self.state_machine = H2ConnectionStateMachine()
self.streams = {}
@@ -325,7 +328,7 @@
)
self.remote_settings = Settings(client=not self.config.client_side)
- # The curent value of the connection flow control windows on the
+ # The current value of the connection flow control windows on the
# connection.
self.outbound_flow_control_window = (
self.remote_settings.initial_window_size
@@ -355,7 +358,9 @@
# Also used to determine whether we should consider a frame received
# while a stream is closed as either a stream error or a connection
# error.
- self._closed_streams = {}
+ self._closed_streams = SizeLimitDict(
+ size_limit=self.MAX_CLOSED_STREAMS
+ )
# The flow control window manager for the connection.
self._inbound_flow_control_window_manager = WindowManager(
@@ -909,16 +914,21 @@
frames = stream.increase_flow_control_window(
increment
)
+
+ self.config.logger.debug(
+ "Increase stream ID %d flow control window by %d",
+ stream_id, increment
+ )
else:
self._inbound_flow_control_window_manager.window_opened(increment)
f = WindowUpdateFrame(0)
f.window_increment = increment
frames = [f]
- self.config.logger.debug(
- "Increase stream ID %d flow control window by %d",
- stream_id, increment
- )
+ self.config.logger.debug(
+ "Increase connection flow control window by %d", increment
+ )
+
self._prepare_for_sending(frames)
def push_stream(self, stream_id, promised_stream_id, request_headers):
@@ -1327,7 +1337,7 @@
self._prepare_for_sending(frames)
- def data_to_send(self, amt=None):
+ def data_to_send(self, amount=None):
"""
Returns some data for sending out of the internal data buffer.
@@ -1336,19 +1346,19 @@
or less if that much data is not available. It does not perform any
I/O, and so uses a different name.
- :param amt: (optional) The maximum amount of data to return. If not
+ :param amount: (optional) The maximum amount of data to return. If not
set, or set to ``None``, will return as much data as possible.
- :type amt: ``int``
+ :type amount: ``int``
:returns: A bytestring containing the data to send on the wire.
:rtype: ``bytes``
"""
- if amt is None:
+ if amount is None:
data = self._data_to_send
self._data_to_send = b''
return data
else:
- data = self._data_to_send[:amt]
- self._data_to_send = self._data_to_send[amt:]
+ data = self._data_to_send[:amount]
+ self._data_to_send = self._data_to_send[amount:]
return data
def clear_outbound_data_buffer(self):
@@ -1717,15 +1727,19 @@
flags = []
if 'ACK' in frame.flags:
- evt = PingAcknowledged()
- evt.ping_data = frame.opaque_data
- events.append(evt)
+ evt = PingAckReceived()
else:
+ evt = PingReceived()
+
+ # automatically ACK the PING with the same 'opaque data'
f = PingFrame(0)
f.flags = {'ACK'}
f.opaque_data = frame.opaque_data
flags.append(f)
+ evt.ping_data = frame.opaque_data
+ events.append(evt)
+
return flags, events
def _receive_rst_stream_frame(self, frame):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/events.py new/h2-3.1.0/h2/events.py
--- old/h2-3.0.1/h2/events.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/h2/events.py 2019-01-22 18:41:43.000000000 +0100
@@ -356,22 +356,51 @@
)
+class PingReceived(Event):
+ """
+ The PingReceived event is fired whenever a PING is received. It contains
+ the 'opaque data' of the PING frame. A ping acknowledgment with the same
+ 'opaque data' is automatically emitted after receiving a ping.
+
+ .. versionadded:: 3.1.0
+ """
+ def __init__(self):
+ #: The data included on the ping.
+ self.ping_data = None
+
+ def __repr__(self):
+ return "" % (
+ _bytes_representation(self.ping_data),
+ )
+
+
class PingAcknowledged(Event):
"""
- The PingAcknowledged event is fired whenever a user-emitted PING is
- acknowledged. This contains the data in the ACK'ed PING, allowing the
- user to correlate PINGs and calculate RTT.
+ Same as PingAckReceived.
+
+ .. deprecated:: 3.1.0
"""
def __init__(self):
#: The data included on the ping.
self.ping_data = None
def __repr__(self):
- return "" % (
+ return "" % (
_bytes_representation(self.ping_data),
)
+class PingAckReceived(PingAcknowledged):
+ """
+ The PingAckReceived event is fired whenever a PING acknowledgment is
+ received. It contains the 'opaque data' of the PING+ACK frame, allowing the
+ user to correlate PINGs and calculate RTT.
+
+ .. versionadded:: 3.1.0
+ """
+ pass
+
+
class StreamEnded(Event):
"""
The StreamEnded event is fired whenever a stream is ended by a remote
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/settings.py new/h2-3.1.0/h2/settings.py
--- old/h2-3.0.1/h2/settings.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/h2/settings.py 2019-01-22 18:41:43.000000000 +0100
@@ -15,6 +15,12 @@
from h2.errors import ErrorCodes
from h2.exceptions import InvalidSettingsValueError
+try:
+ from collections.abc import MutableMapping
+except ImportError: # pragma: no cover
+ # Python 2.7 compatibility
+ from collections import MutableMapping
+
class SettingCodes(enum.IntEnum):
"""
@@ -49,6 +55,10 @@
#: and value in octets plus an overhead of 32 octets for each header field.
MAX_HEADER_LIST_SIZE = SettingsFrame.MAX_HEADER_LIST_SIZE
+ #: This setting can be used to enable the connect protocol. To enable on a
+ #: client set this to 1.
+ ENABLE_CONNECT_PROTOCOL = SettingsFrame.ENABLE_CONNECT_PROTOCOL
+
def _setting_code_from_int(code):
"""
@@ -88,7 +98,7 @@
)
-class Settings(collections.MutableMapping):
+class Settings(MutableMapping):
"""
An object that encapsulates HTTP/2 settings state.
@@ -135,6 +145,7 @@
SettingCodes.ENABLE_PUSH: collections.deque([int(client)]),
SettingCodes.INITIAL_WINDOW_SIZE: collections.deque([65535]),
SettingCodes.MAX_FRAME_SIZE: collections.deque([16384]),
+ SettingCodes.ENABLE_CONNECT_PROTOCOL: collections.deque([0]),
}
if initial_values is not None:
for key, value in initial_values.items():
@@ -243,6 +254,18 @@
def max_header_list_size(self, value):
self[SettingCodes.MAX_HEADER_LIST_SIZE] = value
+ @property
+ def enable_connect_protocol(self):
+ """
+ The current value of the :data:`ENABLE_CONNECT_PROTOCOL
+ ` setting.
+ """
+ return self[SettingCodes.ENABLE_CONNECT_PROTOCOL]
+
+ @enable_connect_protocol.setter
+ def enable_connect_protocol(self, value):
+ self[SettingCodes.ENABLE_CONNECT_PROTOCOL] = value
+
# Implement the MutableMapping API.
def __getitem__(self, key):
val = self._settings[key][0]
@@ -292,7 +315,7 @@
return NotImplemented
-def _validate_setting(setting, value):
+def _validate_setting(setting, value): # noqa: C901
"""
Confirms that a specific setting has a well-formed value. If the setting is
invalid, returns an error code. Otherwise, returns 0 (NO_ERROR).
@@ -309,5 +332,8 @@
elif setting == SettingCodes.MAX_HEADER_LIST_SIZE:
if value < 0:
return ErrorCodes.PROTOCOL_ERROR
+ elif setting == SettingCodes.ENABLE_CONNECT_PROTOCOL:
+ if value not in (0, 1):
+ return ErrorCodes.PROTOCOL_ERROR
return 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/stream.py new/h2-3.1.0/h2/stream.py
--- old/h2-3.0.1/h2/stream.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/h2/stream.py 2019-01-22 18:41:43.000000000 +0100
@@ -788,7 +788,7 @@
self.max_outbound_frame_size = None
self.request_method = None
- # The curent value of the outbound stream flow control window
+ # The current value of the outbound stream flow control window
self.outbound_flow_control_window = outbound_window_size
# The flow control manager.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2/utilities.py new/h2-3.1.0/h2/utilities.py
--- old/h2-3.0.1/h2/utilities.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/h2/utilities.py 2019-01-22 18:41:43.000000000 +0100
@@ -33,6 +33,7 @@
b':authority', u':authority',
b':path', u':path',
b':status', u':status',
+ b':protocol', u':protocol',
])
@@ -47,13 +48,19 @@
b':scheme', u':scheme',
b':path', u':path',
b':authority', u':authority',
- b':method', u':method'
+ b':method', u':method',
+ b':protocol', u':protocol',
])
_RESPONSE_ONLY_HEADERS = frozenset([b':status', u':status'])
+# A Set of pseudo headers that are only valid if the method is
+# CONNECT, see RFC 8441 § 5
+_CONNECT_REQUEST_ONLY_HEADERS = frozenset([b':protocol', u':protocol'])
+
+
if sys.version_info[0] == 2: # Python 2.X
_WHITESPACE = frozenset(whitespace)
else: # Python 3.3+
@@ -323,6 +330,7 @@
"""
seen_pseudo_header_fields = set()
seen_regular_header = False
+ method = None
for header in headers:
if _custom_startswith(header[0], b':', u':'):
@@ -344,6 +352,12 @@
"Received custom pseudo-header field %s" % header[0]
)
+ if header[0] in (b':method', u':method'):
+ if not isinstance(header[1], bytes):
+ method = header[1].encode('utf-8')
+ else:
+ method = header[1]
+
else:
seen_regular_header = True
@@ -351,11 +365,12 @@
# Check the pseudo-headers we got to confirm they're acceptable.
_check_pseudo_header_field_acceptability(
- seen_pseudo_header_fields, hdr_validation_flags
+ seen_pseudo_header_fields, method, hdr_validation_flags
)
def _check_pseudo_header_field_acceptability(pseudo_headers,
+ method,
hdr_validation_flags):
"""
Given the set of pseudo-headers present in a header block and the
@@ -394,6 +409,13 @@
"Encountered response-only headers %s" %
invalid_request_headers
)
+ if method != b'CONNECT':
+ invalid_headers = pseudo_headers & _CONNECT_REQUEST_ONLY_HEADERS
+ if invalid_headers:
+ raise ProtocolError(
+ "Encountered connect-request-only headers %s" %
+ invalid_headers
+ )
def _validate_host_authority_header(headers):
@@ -617,3 +639,22 @@
headers = _check_path_header(headers, hdr_validation_flags)
return headers
+
+
+class SizeLimitDict(collections.OrderedDict):
+
+ def __init__(self, *args, **kwargs):
+ self._size_limit = kwargs.pop("size_limit", None)
+ super(SizeLimitDict, self).__init__(*args, **kwargs)
+
+ self._check_size_limit()
+
+ def __setitem__(self, key, value):
+ super(SizeLimitDict, self).__setitem__(key, value)
+
+ self._check_size_limit()
+
+ def _check_size_limit(self):
+ if self._size_limit is not None:
+ while len(self) > self._size_limit:
+ self.popitem(last=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2.egg-info/PKG-INFO new/h2-3.1.0/h2.egg-info/PKG-INFO
--- old/h2-3.0.1/h2.egg-info/PKG-INFO 2017-04-03 10:07:26.000000000 +0200
+++ new/h2-3.1.0/h2.egg-info/PKG-INFO 2019-01-22 18:42:26.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: h2
-Version: 3.0.1
+Version: 3.1.0
Summary: HTTP/2 State-Machine based protocol implementation
Home-page: http://hyper.rtfd.org
Author: Cory Benfield
@@ -76,6 +76,38 @@
Release History
===============
+ 3.1.0 (2019-01-22)
+ ------------------
+
+ API Changes (Backward-Incompatible)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - ``h2.connection.H2Connection.data_to_send`` first and only argument ``amt``
+ was renamed to ``amount``.
+ - Support for Python 3.3 has been removed.
+
+ API Changes (Backward-Compatible)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - ``h2.connection.H2Connection.send_data`` now supports ``data`` parameter
+ being a ``memoryview`` object.
+ - Refactor ping-related events: a ``h2.events.PingReceived`` event is fired
+ when a PING frame is received and a ``h2.events.PingAckReceived`` event is
+ fired when a PING frame with an ACK flag is received.
+ ``h2.events.PingAcknowledged`` is deprecated in favour of the identical
+ ``h2.events.PingAckReceived``.
+ - Added ``ENABLE_CONNECT_PROTOCOL`` to ``h2.settings.SettingCodes``.
+ - Support ``CONNECT`` requests with a ``:protocol`` pseudo header
+ thereby supporting RFC 8441.
+ - A limit to the number of closed streams kept in memory by the
+ connection is applied. It can be configured by
+ ``h2.connection.H2Connection.MAX_CLOSED_STREAMS``.
+
+ Bugfixes
+ ~~~~~~~~
+
+ - Debug logging when stream_id is None is now fixed and no longer errors.
+
3.0.1 (2017-04-03)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2.egg-info/SOURCES.txt new/h2-3.1.0/h2.egg-info/SOURCES.txt
--- old/h2-3.0.1/h2.egg-info/SOURCES.txt 2017-04-03 10:07:26.000000000 +0200
+++ new/h2-3.1.0/h2.egg-info/SOURCES.txt 2019-01-22 18:42:26.000000000 +0100
@@ -95,6 +95,7 @@
test/test_priority.py
test/test_related_events.py
test/test_rfc7838.py
+test/test_rfc8441.py
test/test_settings.py
test/test_state_machines.py
test/test_stream_reset.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/h2.egg-info/requires.txt new/h2-3.1.0/h2.egg-info/requires.txt
--- old/h2-3.0.1/h2.egg-info/requires.txt 2017-04-03 10:07:26.000000000 +0200
+++ new/h2-3.1.0/h2.egg-info/requires.txt 2019-01-22 18:42:26.000000000 +0100
@@ -1,5 +1,5 @@
-hyperframe>=5.0, <6
-hpack>=2.3, <4
+hyperframe<6,>=5.2.0
+hpack<4,>=2.3
[:python_version == "2.7" or python_version == "3.3"]
-enum34>=1.1.6, <2
+enum34<2,>=1.1.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/setup.py new/h2-3.1.0/setup.py
--- old/h2-3.0.1/setup.py 2017-04-03 09:57:49.000000000 +0200
+++ new/h2-3.1.0/setup.py 2019-01-22 18:41:43.000000000 +0100
@@ -62,8 +62,8 @@
'Programming Language :: Python :: Implementation :: PyPy',
],
install_requires=[
- 'hyperframe>=5.0, <6',
- 'hpack>=2.3, <4',
+ 'hyperframe>=5.2.0, <6',
+ 'hpack>=2.3,<4',
],
extras_require={
':python_version == "2.7" or python_version == "3.3"': ['enum34>=1.1.6, <2'],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_basic_logic.py new/h2-3.1.0/test/test_basic_logic.py
--- old/h2-3.0.1/test/test_basic_logic.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/test/test_basic_logic.py 2019-01-22 18:41:43.000000000 +0100
@@ -114,6 +114,23 @@
expected_data_frame_pad_length=0
)
+ def test_sending_data_in_memoryview(self):
+ """
+ Support memoryview for sending data.
+ """
+ c = h2.connection.H2Connection()
+ c.initiate_connection()
+ c.send_headers(1, self.example_request_headers)
+
+ # Clear the data, then send some data.
+ c.clear_outbound_data_buffer()
+ events = c.send_data(1, memoryview(b'some data'))
+ assert not events
+ data_to_send = c.data_to_send()
+ assert (
+ data_to_send == b'\x00\x00\t\x00\x00\x00\x00\x00\x01some data'
+ )
+
def test_sending_data_with_padding(self):
"""
Single data frames with padding are encoded correctly.
@@ -1081,7 +1098,12 @@
c.clear_outbound_data_buffer()
events = c.receive_data(sent_frame.serialize())
- assert not events
+ assert len(events) == 1
+ event = events[0]
+
+ assert isinstance(event, h2.events.PingReceived)
+ assert event.ping_data == ping_data
+
assert c.data_to_send() == expected_data
def test_receiving_settings_frame_event(self, frame_factory):
@@ -1324,7 +1346,7 @@
def test_receiving_ping_acknowledgement(self, frame_factory):
"""
- Receiving a PING acknolwedgement fires a PingAcknolwedged event.
+ Receiving a PING acknowledgement fires a PingAckReceived event.
"""
c = h2.connection.H2Connection(config=self.server_config)
c.receive_data(frame_factory.preamble())
@@ -1339,7 +1361,8 @@
assert len(events) == 1
event = events[0]
- assert isinstance(event, h2.events.PingAcknowledged)
+ assert isinstance(event, h2.events.PingAckReceived)
+ assert isinstance(event, h2.events.PingAcknowledged) # deprecated
assert event.ping_data == ping_data
def test_stream_ended_remotely(self, frame_factory):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_events.py new/h2-3.1.0/test/test_events.py
--- old/h2-3.0.1/test/test_events.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/test/test_events.py 2019-01-22 18:41:43.000000000 +0100
@@ -213,14 +213,23 @@
"new_value=32768)}>"
)
- def test_pingacknowledged_repr(self):
+ def test_pingreceived_repr(self):
"""
- PingAcknowledged has a useful debug representation.
+ PingReceived has a useful debug representation.
"""
- e = h2.events.PingAcknowledged()
+ e = h2.events.PingReceived()
e.ping_data = b'abcdefgh'
- assert repr(e) == "<PingAcknowledged ping_data:6162636465666768>"
+ assert repr(e) == "<PingReceived ping_data:6162636465666768>"
+
+ def test_pingackreceived_repr(self):
+ """
+ PingAckReceived has a useful debug representation.
+ """
+ e = h2.events.PingAckReceived()
+ e.ping_data = b'abcdefgh'
+
+ assert repr(e) == "<PingAckReceived ping_data:6162636465666768>"
def test_streamended_repr(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_invalid_headers.py new/h2-3.1.0/test/test_invalid_headers.py
--- old/h2-3.0.1/test/test_invalid_headers.py 2017-04-03 09:57:49.000000000 +0200
+++ new/h2-3.1.0/test/test_invalid_headers.py 2019-01-22 18:41:43.000000000 +0100
@@ -54,6 +54,7 @@
base_request_headers + [('name', 'value with trailing space ')],
[header for header in base_request_headers
if header[0] != ':authority'],
+ [(':protocol', 'websocket')] + base_request_headers,
]
server_config = h2.config.H2Configuration(
client_side=False, header_encoding='utf-8'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_rfc8441.py new/h2-3.1.0/test/test_rfc8441.py
--- old/h2-3.0.1/test/test_rfc8441.py 1970-01-01 01:00:00.000000000 +0100
+++ new/h2-3.1.0/test/test_rfc8441.py 2019-01-22 18:41:43.000000000 +0100
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+"""
+test_rfc8441
+~~~~~~~~~~~~
+
+Test the RFC 8441 extended connect request support.
+"""
+import h2.config
+import h2.connection
+import h2.events
+
+
+class TestRFC8441(object):
+ """
+ Tests that the client supports sending an extended connect request
+ and the server supports receiving it.
+ """
+
+ def test_can_send_headers(self, frame_factory):
+ headers = [
+ (b':authority', b'example.com'),
+ (b':path', b'/'),
+ (b':scheme', b'https'),
+ (b':method', b'CONNECT'),
+ (b':protocol', b'websocket'),
+ (b'user-agent', b'someua/0.0.1'),
+ ]
+
+ client = h2.connection.H2Connection()
+ client.initiate_connection()
+ client.send_headers(stream_id=1, headers=headers)
+
+ server = h2.connection.H2Connection(
+ config=h2.config.H2Configuration(client_side=False)
+ )
+ events = server.receive_data(client.data_to_send())
+ event = events[1]
+ assert isinstance(event, h2.events.RequestReceived)
+ assert event.stream_id == 1
+ assert event.headers == headers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_settings.py new/h2-3.1.0/test/test_settings.py
--- old/h2-3.0.1/test/test_settings.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/test/test_settings.py 2019-01-22 18:41:43.000000000 +0100
@@ -12,7 +12,9 @@
import h2.settings
from hypothesis import given, assume
-from hypothesis.strategies import integers
+from hypothesis.strategies import (
+ integers, booleans, fixed_dictionaries, builds
+)
class TestSettings(object):
@@ -29,6 +31,7 @@
assert s[h2.settings.SettingCodes.ENABLE_PUSH] == 1
assert s[h2.settings.SettingCodes.INITIAL_WINDOW_SIZE] == 65535
assert s[h2.settings.SettingCodes.MAX_FRAME_SIZE] == 16384
+ assert s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] == 0
def test_settings_defaults_server(self):
"""
@@ -40,6 +43,7 @@
assert s[h2.settings.SettingCodes.ENABLE_PUSH] == 0
assert s[h2.settings.SettingCodes.INITIAL_WINDOW_SIZE] == 65535
assert s[h2.settings.SettingCodes.MAX_FRAME_SIZE] == 16384
+ assert s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] == 0
@pytest.mark.parametrize('client', [True, False])
def test_can_set_initial_values(self, client):
@@ -52,6 +56,7 @@
h2.settings.SettingCodes.MAX_FRAME_SIZE: 16388,
h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100,
h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 2**16,
+ h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL: 1,
}
s = h2.settings.Settings(client=client, initial_values=overrides)
@@ -61,6 +66,7 @@
assert s[h2.settings.SettingCodes.MAX_FRAME_SIZE] == 16388
assert s[h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS] == 100
assert s[h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE] == 2**16
+ assert s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] == 1
@pytest.mark.parametrize(
'setting,value',
@@ -72,6 +78,7 @@
(h2.settings.SettingCodes.MAX_FRAME_SIZE, 1),
(h2.settings.SettingCodes.MAX_FRAME_SIZE, 2**30),
(h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE, -1),
+ (h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL, -1),
]
)
def test_cannot_set_invalid_initial_values(self, setting, value):
@@ -106,6 +113,7 @@
h2.settings.SettingCodes.ENABLE_PUSH: 0,
h2.settings.SettingCodes.INITIAL_WINDOW_SIZE: 60,
h2.settings.SettingCodes.MAX_FRAME_SIZE: 16385,
+ h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL: 1,
}
s.update(new_settings)
@@ -169,16 +177,16 @@
Length is related only to the number of keys.
"""
s = h2.settings.Settings(client=True)
- assert len(s) == 4
+ assert len(s) == 5
s[h2.settings.SettingCodes.HEADER_TABLE_SIZE] == 8000
- assert len(s) == 4
+ assert len(s) == 5
s.acknowledge()
- assert len(s) == 4
+ assert len(s) == 5
del s[h2.settings.SettingCodes.HEADER_TABLE_SIZE]
- assert len(s) == 3
+ assert len(s) == 4
def test_new_values_work(self):
"""
@@ -232,6 +240,9 @@
assert s.max_frame_size == s[h2.settings.SettingCodes.MAX_FRAME_SIZE]
assert s.max_concurrent_streams == 2**32 + 1 # A sensible default.
assert s.max_header_list_size is None
+ assert s.enable_connect_protocol == s[
+ h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL
+ ]
def test_settings_setters(self):
"""
@@ -245,6 +256,7 @@
s.max_frame_size = 16385
s.max_concurrent_streams = 4
s.max_header_list_size = 2**16
+ s.enable_connect_protocol = 1
s.acknowledge()
assert s[h2.settings.SettingCodes.HEADER_TABLE_SIZE] == 0
@@ -253,6 +265,7 @@
assert s[h2.settings.SettingCodes.MAX_FRAME_SIZE] == 16385
assert s[h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS] == 4
assert s[h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE] == 2**16
+ assert s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] == 1
@given(integers())
def test_cannot_set_invalid_values_for_enable_push(self, val):
@@ -361,131 +374,97 @@
with pytest.raises(KeyError):
s[h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE]
-
-class TestSettingsEquality(object):
- """
- A class defining tests for the standard implementation of == and != .
- """
-
- def an_instance(self):
+ @given(integers())
+ def test_cannot_set_invalid_values_for_enable_connect_protocol(self, val):
"""
- Return an instance of the class under test. Each call to this method
- must return a different object. All objects returned must be equal to
- each other.
+ SETTINGS_ENABLE_CONNECT_PROTOCOL only allows two values: 0, 1.
"""
- overrides = {
- h2.settings.SettingCodes.HEADER_TABLE_SIZE: 0,
- h2.settings.SettingCodes.MAX_FRAME_SIZE: 16384,
- h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 4,
- h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 2**16,
- }
- return h2.settings.Settings(client=True, initial_values=overrides)
+ assume(val not in (0, 1))
+ s = h2.settings.Settings()
- def another_instance(self):
- """
- Return an instance of the class under test. Each call to this method
- must return a different object. The objects must not be equal to the
- objects returned by an_instance. They may or may not be equal to
- each other (they will not be compared against each other).
- """
- overrides = {
- h2.settings.SettingCodes.HEADER_TABLE_SIZE: 8080,
- h2.settings.SettingCodes.MAX_FRAME_SIZE: 16388,
- h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100,
- h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 2**16,
- }
- return h2.settings.Settings(client=False, initial_values=overrides)
+ with pytest.raises(h2.exceptions.InvalidSettingsValueError) as e:
+ s.enable_connect_protocol = val
- def test_identical_eq(self):
- """
- An object compares equal to itself using the == operator.
- """
- o = self.an_instance()
- assert (o == o)
+ s.acknowledge()
+ assert e.value.error_code == h2.errors.ErrorCodes.PROTOCOL_ERROR
+ assert s.enable_connect_protocol == 0
- def test_identical_ne(self):
- """
- An object doesn't compare not equal to itself using the != operator.
- """
- o = self.an_instance()
- assert not (o != o)
+ with pytest.raises(h2.exceptions.InvalidSettingsValueError) as e:
+ s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] = val
- def test_same_eq(self):
- """
- Two objects that are equal to each other compare equal to each other
- using the == operator.
- """
- a = self.an_instance()
- b = self.an_instance()
- assert (a == b)
+ s.acknowledge()
+ assert e.value.error_code == h2.errors.ErrorCodes.PROTOCOL_ERROR
+ assert s[h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL] == 0
- def test_same_ne(self):
- """
- Two objects that are equal to each other do not compare not equal to
- each other using the != operator.
- """
- a = self.an_instance()
- b = self.an_instance()
- assert not (a != b)
- def test_different_eq(self):
+class TestSettingsEquality(object):
+ """
+ A class defining tests for the standard implementation of == and != .
+ """
+
+ SettingsStrategy = builds(
+ h2.settings.Settings,
+ client=booleans(),
+ initial_values=fixed_dictionaries({
+ h2.settings.SettingCodes.HEADER_TABLE_SIZE:
+ integers(0, 2**32 - 1),
+ h2.settings.SettingCodes.ENABLE_PUSH: integers(0, 1),
+ h2.settings.SettingCodes.INITIAL_WINDOW_SIZE:
+ integers(0, 2**31 - 1),
+ h2.settings.SettingCodes.MAX_FRAME_SIZE:
+ integers(2**14, 2**24 - 1),
+ h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS:
+ integers(0, 2**32 - 1),
+ h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE:
+ integers(0, 2**32 - 1),
+ })
+ )
+
+ @given(settings=SettingsStrategy)
+ def test_equality_reflexive(self, settings):
"""
- Two objects that are not equal to each other do not compare equal to
- each other using the == operator.
+ An object compares equal to itself using the == operator and the !=
+ operator.
"""
- a = self.an_instance()
- b = self.another_instance()
- assert not (a == b)
+ assert (settings == settings)
+ assert not (settings != settings)
- def test_different_ne(self):
+ @given(settings=SettingsStrategy, o_settings=SettingsStrategy)
+ def test_equality_multiple(self, settings, o_settings):
"""
- Two objects that are not equal to each other compare not equal to each
- other using the != operator.
+ Two objects compare themselves using the == operator and the !=
+ operator.
"""
- a = self.an_instance()
- b = self.another_instance()
- assert (a != b)
+ if settings == o_settings:
+ assert settings == o_settings
+ assert not (settings != o_settings)
+ else:
+ assert settings != o_settings
+ assert not (settings == o_settings)
- def test_another_type_eq(self):
+ @given(settings=SettingsStrategy)
+ def test_another_type_equality(self, settings):
"""
The object does not compare equal to an object of an unrelated type
(which does not implement the comparison) using the == operator.
"""
- a = self.an_instance()
- b = object()
- assert not (a == b)
+ obj = object()
+ assert (settings != obj)
+ assert not (settings == obj)
- def test_another_type_ne(self):
+ @given(settings=SettingsStrategy)
+ def test_delegated_eq(self, settings):
"""
- The object compares not equal to an object of an unrelated type (which
- does not implement the comparison) using the != operator.
- """
- a = self.an_instance()
- b = object()
- assert (a != b)
-
- def test_delegated_eq(self):
- """
- The result of comparison using == is delegated to the right-hand
- operand if it is of an unrelated type.
+ The result of comparison is delegated to the right-hand operand if
+ it is of an unrelated type.
"""
class Delegate(object):
def __eq__(self, other):
return [self]
- a = self.an_instance()
- b = Delegate()
- assert (a == b) == [b]
-
- def test_delegate_ne(self):
- """
- The result of comparison using != is delegated to the right-hand
- operand if it is of an unrelated type.
- """
- class Delegate(object):
def __ne__(self, other):
return [self]
- a = self.an_instance()
- b = Delegate()
- assert (a != b) == [b]
+ delg = Delegate()
+ assert (settings == delg) == [delg]
+ assert (settings != delg) == [delg]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test/test_utility_functions.py new/h2-3.1.0/test/test_utility_functions.py
--- old/h2-3.0.1/test/test_utility_functions.py 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/test/test_utility_functions.py 2019-01-22 18:41:43.000000000 +0100
@@ -12,7 +12,7 @@
import h2.errors
import h2.events
import h2.exceptions
-from h2.utilities import extract_method_header
+from h2.utilities import SizeLimitDict, extract_method_header
# These tests require a non-list-returning range function.
try:
@@ -176,3 +176,51 @@
)
def test_extract_header_method(self, headers):
assert extract_method_header(headers) == b'GET'
+
+
+def test_size_limit_dict_limit():
+ dct = SizeLimitDict(size_limit=2)
+
+ dct[1] = 1
+ dct[2] = 2
+
+ assert len(dct) == 2
+ assert dct[1] == 1
+ assert dct[2] == 2
+
+ dct[3] = 3
+
+ assert len(dct) == 2
+ assert dct[2] == 2
+ assert dct[3] == 3
+ assert 1 not in dct
+
+
+def test_size_limit_dict_limit_init():
+ initial_dct = {
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ }
+
+ dct = SizeLimitDict(initial_dct, size_limit=2)
+
+ assert len(dct) == 2
+
+
+def test_size_limit_dict_no_limit():
+ dct = SizeLimitDict(size_limit=None)
+
+ dct[1] = 1
+ dct[2] = 2
+
+ assert len(dct) == 2
+ assert dct[1] == 1
+ assert dct[2] == 2
+
+ dct[3] = 3
+
+ assert len(dct) == 3
+ assert dct[1] == 1
+ assert dct[2] == 2
+ assert dct[3] == 3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/test_requirements.txt new/h2-3.1.0/test_requirements.txt
--- old/h2-3.0.1/test_requirements.txt 2017-03-31 17:30:40.000000000 +0200
+++ new/h2-3.1.0/test_requirements.txt 2019-01-22 18:41:43.000000000 +0100
@@ -1,5 +1,5 @@
-pytest==3.0.7
-pytest-cov==2.4.0
-coverage==4.3.4
-pytest-xdist==1.15.0
-hypothesis==3.7.0
+pytest==3.4.2
+pytest-cov==2.5.1
+coverage==4.5.1
+pytest-xdist==1.22.2
+hypothesis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/tox.ini new/h2-3.1.0/tox.ini
--- old/h2-3.0.1/tox.ini 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/tox.ini 2019-01-22 18:41:43.000000000 +0100
@@ -1,5 +1,5 @@
[tox]
-envlist = py27, py33, py34, py35, py36, pypy, lint, packaging, docs
+envlist = py27, py34, py35, py36, py37, pypy, lint, packaging, docs
[testenv]
deps= -r{toxinidir}/test_requirements.txt
@@ -15,22 +15,17 @@
# This is a validation test that confirms that Twisted's test cases haven't
# broken.
deps =
- # [tls,http2] syntax doesn't work here so we enumerate all dependencies.
- git+https://github.com/twisted/twisted
- pyopenssl
- service_identity
- idna
- priority
+ twisted[tls, http2, conch]
sphinx
commands = python -m twisted.trial --reporter=text twisted
[testenv:lint]
-basepython=python3.4
-deps = flake8==3.3.0
+basepython=python3.7
+deps = flake8==3.5.0
commands = flake8 --max-complexity 10 h2 test
[testenv:docs]
-basepython=python3.5
+basepython=python3.7
deps = sphinx==1.4.9
changedir = {toxinidir}/docs
whitelist_externals = rm
@@ -40,15 +35,15 @@
[testenv:graphs]
basepython=python2.7
-deps = graphviz==0.6
+deps = graphviz==0.8.2
commands =
python visualizer/visualize.py -i docs/source/_static
[testenv:packaging]
-basepython=python2.7
+basepython=python3.7
deps =
- check-manifest==0.35
- readme_renderer==17.2
+ check-manifest==0.36
+ readme-renderer==17.3
commands =
check-manifest
python setup.py check --metadata --restructuredtext --strict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/h2-3.0.1/utils/backport.sh new/h2-3.1.0/utils/backport.sh
--- old/h2-3.0.1/utils/backport.sh 2017-04-03 09:57:46.000000000 +0200
+++ new/h2-3.1.0/utils/backport.sh 2019-01-22 18:41:43.000000000 +0100
@@ -16,6 +16,7 @@
if ! git pull --ff-only; then
echo "Unable to update $TARGET_BRANCH"
exit 2
+fi
if ! git checkout -b "$PR_BRANCH"; then
echo "Failed to open new branch $PR_BRANCH"