From 27c725d740b2923438bca95bc081adcdbe6dceb1 Mon Sep 17 00:00:00 2001 From: Nate Prewitt Date: Thu, 1 Dec 2016 10:18:45 -0700 Subject: [PATCH] adding HTTP version flags to connections and responses --- hyper/common/util.py | 10 ++++++++++ hyper/http11/connection.py | 5 ++++- hyper/http11/response.py | 4 ++++ hyper/http20/connection.py | 7 ++++++- hyper/http20/response.py | 4 ++++ setup.py | 3 ++- test/test_http11.py | 13 +++++++++++++ test/test_hyper.py | 10 +++++++++- 8 files changed, 52 insertions(+), 4 deletions(-) diff --git a/hyper/common/util.py b/hyper/common/util.py index 6d199a0c..a2278b54 100644 --- a/hyper/common/util.py +++ b/hyper/common/util.py @@ -5,6 +5,8 @@ General utility functions for use with hyper. """ +from enum import Enum + from hyper.compat import unicode, bytes, imap from ..packages.rfc3986.uri import URIReference from ..compat import is_py3 @@ -57,3 +59,11 @@ def to_native_string(string, encoding='utf-8'): return string return string.decode(encoding) if is_py3 else string.encode(encoding) + + +class HTTPVersion(Enum): + """ + Collection of all HTTP versions used in hyper. + """ + http11 = "HTTP/1.1" + http20 = "HTTP/2" diff --git a/hyper/http11/connection.py b/hyper/http11/connection.py index 61361c35..4512fdbd 100644 --- a/hyper/http11/connection.py +++ b/hyper/http11/connection.py @@ -20,7 +20,7 @@ from ..common.bufsocket import BufferedSocket from ..common.exceptions import TLSUpgrade, HTTPUpgrade from ..common.headers import HTTPHeaderMap -from ..common.util import to_bytestring, to_host_port_tuple +from ..common.util import to_bytestring, to_host_port_tuple, HTTPVersion from ..compat import bytes # We prefer pycohttpparser to the pure-Python interpretation @@ -63,6 +63,9 @@ def __init__(self, host, port=None, secure=None, ssl_context=None, else: self.host, self.port = host, port + # Version of the HTTP connection + self.version = HTTPVersion.http11 + # Record whether we plan to secure the request. In future this should # be extended to a security profile, but a bool will do for now. # TODO: Actually do something with this! diff --git a/hyper/http11/response.py b/hyper/http11/response.py index ee23be08..a7dd2267 100644 --- a/hyper/http11/response.py +++ b/hyper/http11/response.py @@ -13,6 +13,7 @@ from ..common.decoder import DeflateDecoder from ..common.exceptions import ChunkedDecodeError, InvalidResponseError from ..common.exceptions import ConnectionResetError +from ..common.util import HTTPVersion log = logging.getLogger(__name__) @@ -34,6 +35,9 @@ def __init__(self, code, reason, headers, sock, connection=None): #: once, and never assigned again. self.headers = headers + #: HTTP Version of the response + self.version = HTTPVersion.http11 + #: The response trailers. These are always intially ``None``. self.trailers = None diff --git a/hyper/http20/connection.py b/hyper/http20/connection.py index 31dc7a47..c055e401 100644 --- a/hyper/http20/connection.py +++ b/hyper/http20/connection.py @@ -14,7 +14,9 @@ from ..common.exceptions import ConnectionResetError from ..common.bufsocket import BufferedSocket from ..common.headers import HTTPHeaderMap -from ..common.util import to_host_port_tuple, to_native_string, to_bytestring +from ..common.util import ( + to_host_port_tuple, to_native_string, to_bytestring, HTTPVersion +) from ..compat import unicode, bytes from .stream import Stream from .response import HTTP20Response, HTTP20Push @@ -102,6 +104,9 @@ def __init__(self, host, port=None, secure=None, window_manager=None, else: self.host, self.port = host, port + # HTTP Version of the connection + self.version = HTTPVersion.http20 + if secure is not None: self.secure = secure elif self.port == 443: diff --git a/hyper/http20/response.py b/hyper/http20/response.py index bb339b2f..19f30418 100644 --- a/hyper/http20/response.py +++ b/hyper/http20/response.py @@ -11,6 +11,7 @@ from ..common.decoder import DeflateDecoder from ..common.headers import HTTPHeaderMap +from ..common.util import HTTPVersion log = logging.getLogger(__name__) @@ -51,6 +52,9 @@ def __init__(self, headers, stream): #: once, and never assigned again. self.headers = headers + #: HTTP Version of the response + self.version = HTTPVersion.http20 + # The response trailers. These are always intially ``None``. self._trailers = None diff --git a/setup.py b/setup.py index 0d36afaa..083db831 100644 --- a/setup.py +++ b/setup.py @@ -96,6 +96,7 @@ def run_tests(self): # module at lower than 1.0, because it doesn't support CFFI v1.0 yet. ':platform_python_implementation == "PyPy" and python_full_version < "2.7.9"': [ 'cryptography<1.0' - ] + ], + ':python_version == "2.7" or python_version == "3.3"': ['enum34>=1.0.4, <2'] } ) diff --git a/test/test_http11.py b/test/test_http11.py index d4039588..5f0fcf7a 100644 --- a/test/test_http11.py +++ b/test/test_http11.py @@ -19,6 +19,7 @@ from hyper.http11.response import HTTP11Response from hyper.common.headers import HTTPHeaderMap from hyper.common.exceptions import ChunkedDecodeError, ConnectionResetError +from hyper.common.util import HTTPVersion from hyper.compat import bytes, zlib_compressobj @@ -838,6 +839,18 @@ def test_closing_chunked_reads_dont_call_close_callback(self): assert r._sock is None assert connection.close.call_count == 1 + def test_connection_version(self): + c = HTTP11Connection('httpbin.org') + assert c.version is HTTPVersion.http11 + + def test_response_version(self): + d = DummySocket() + headers = { + b'transfer-encoding': [b'chunked'], b'connection': [b'close'] + } + r = HTTP11Response(200, 'OK', headers, d) + assert r.version is HTTPVersion.http11 + class DummySocket(object): def __init__(self): diff --git a/test/test_hyper.py b/test/test_hyper.py index da0aad57..59d354c7 100644 --- a/test/test_hyper.py +++ b/test/test_hyper.py @@ -16,7 +16,7 @@ combine_repeated_headers, split_repeated_headers, h2_safe_headers ) from hyper.common.headers import HTTPHeaderMap -from hyper.common.util import to_bytestring +from hyper.common.util import to_bytestring, HTTPVersion from hyper.compat import zlib_compressobj, is_py2 from hyper.contrib import HTTP20Adapter import hyper.http20.errors as errors @@ -82,6 +82,10 @@ def test_connections_can_parse_ipv6_hosts_and_ports(self): assert c.proxy_host == 'ffff:aaaa::1' assert c.proxy_port == 8443 + def test_connection_version(self): + c = HTTP20Connection('www.google.com') + assert c.version is HTTPVersion.http20 + def test_ping(self, frame_buffer): def data_callback(chunk, **kwargs): frame_buffer.add_data(chunk) @@ -1097,6 +1101,10 @@ def test_read_compressed_frames(self): assert received == b'this is test data' + def test_response_version(self): + r = HTTP20Response(HTTPHeaderMap([(':status', '200')]), None) + assert r.version is HTTPVersion.http20 + class TestHTTP20Adapter(object): def test_adapter_reuses_connections(self):