Skip to content
This repository was archived by the owner on Jan 13, 2021. It is now read-only.

Commit 222bedc

Browse files
committed
Merge pull request #125 from Lukasa/alpn
ALPN Support
2 parents fd3c54b + 70924f0 commit 222bedc

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

hyper/ssl_compat.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ def selected_npn_protocol(self):
149149

150150
return proto if proto else None
151151

152+
def selected_alpn_protocol(self):
153+
proto = self._conn.get_alpn_proto_negotiated()
154+
if isinstance(proto, bytes):
155+
proto = proto.decode('ascii')
156+
157+
return proto if proto else None
158+
152159
def getpeercert(self):
153160
def resolve_alias(alias):
154161
return dict(
@@ -246,6 +253,10 @@ def cb(conn, protos):
246253

247254
self._ctx.set_npn_select_callback(cb)
248255

256+
def set_alpn_protocols(self, protocols):
257+
protocols = list(map(lambda x: x.encode('ascii'), protocols))
258+
self._ctx.set_alpn_protos(protocols)
259+
249260
def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True,
250261
suppress_ragged_eofs=True, server_hostname=None):
251262
conn = ossl.Connection(self._ctx, sock)

hyper/tls.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
NPN_PROTOCOL = 'h2'
14-
H2_NPN_PROTOCOLS = [NPN_PROTOCOL, 'h2-16', 'h2-15', 'h2-14'] # All h2s we support.
14+
H2_NPN_PROTOCOLS = [NPN_PROTOCOL, 'h2-16', 'h2-15', 'h2-14']
1515
SUPPORTED_NPN_PROTOCOLS = H2_NPN_PROTOCOLS + ['http/1.1']
1616

1717

@@ -22,6 +22,7 @@
2222
# Work out where our certificates are.
2323
cert_loc = path.join(path.dirname(__file__), 'certs.pem')
2424

25+
2526
def wrap_socket(sock, server_hostname):
2627
"""
2728
A vastly simplified SSL wrapping function. We'll probably extend this to
@@ -35,17 +36,24 @@ def wrap_socket(sock, server_hostname):
3536
# the spec requires SNI support
3637
ssl_sock = _context.wrap_socket(sock, server_hostname=server_hostname)
3738
# Setting SSLContext.check_hostname to True only verifies that the
38-
# post-handshake servername matches that of the certificate. We also need to
39-
# check that it matches the requested one.
39+
# post-handshake servername matches that of the certificate. We also need
40+
# to check that it matches the requested one.
4041
if _context.check_hostname: # pragma: no cover
4142
try:
4243
ssl.match_hostname(ssl_sock.getpeercert(), server_hostname)
4344
except AttributeError:
4445
ssl.verify_hostname(ssl_sock, server_hostname) # pyopenssl
4546

4647
proto = None
48+
49+
# ALPN is newer, so we prefer it over NPN. The odds of us getting different
50+
# answers is pretty low, but let's be sure.
51+
with ignore_missing():
52+
proto = ssl_sock.selected_alpn_protocol()
53+
4754
with ignore_missing():
48-
proto = ssl_sock.selected_npn_protocol()
55+
if proto is None:
56+
proto = ssl_sock.selected_npn_protocol()
4957

5058
return (ssl_sock, proto)
5159

@@ -63,6 +71,9 @@ def _init_context():
6371
with ignore_missing():
6472
context.set_npn_protocols(SUPPORTED_NPN_PROTOCOLS)
6573

74+
with ignore_missing():
75+
context.set_alpn_protocols(SUPPORTED_NPN_PROTOCOLS)
76+
6677
# required by the spec
6778
context.options |= ssl.OP_NO_COMPRESSION
6879

0 commit comments

Comments
 (0)