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

Commit 97e529e

Browse files
committed
Fixing HTTP upgrade functionality
1 parent c860485 commit 97e529e

File tree

4 files changed

+42
-17
lines changed

4 files changed

+42
-17
lines changed

hyper/common/connection.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def __init__(self,
5555
self._h1_kwargs = {'secure': secure, 'ssl_context': ssl_context}
5656
self._h2_kwargs = {
5757
'window_manager': window_manager, 'enable_push': enable_push,
58-
'ssl_context': ssl_context
58+
'secure': secure, 'ssl_context': ssl_context
5959
}
6060

6161
# Add any unexpected kwargs to both dictionaries.
@@ -87,14 +87,11 @@ def request(self, method, url, body=None, headers={}):
8787
return self._conn.request(
8888
method=method, url=url, body=body, headers=headers
8989
)
90-
except (TLSUpgrade, HTTPUpgrade) as e:
91-
# We upgraded in the NPN/ALPN handshake or via the HTTP Upgrade
92-
# mechanism. We can just go straight to the world of HTTP/2.
93-
#Replace the backing object and insert the socket into it.
94-
if(type(e) is TLSUpgrade):
95-
assert e.negotiated in H2_NPN_PROTOCOLS
96-
else:
97-
assert e.negotiated == H2C_PROTOCOL
90+
except TLSUpgrade as e:
91+
# We upgraded in the NPN/ALPN handshake. We can just go straight to
92+
# the world of HTTP/2. Replace the backing object and insert the
93+
# socket into it.
94+
assert e.negotiated in H2_NPN_PROTOCOLS
9895

9996
self._conn = HTTP20Connection(
10097
self._host, self._port, **self._h2_kwargs
@@ -109,6 +106,31 @@ def request(self, method, url, body=None, headers={}):
109106
method=method, url=url, body=body, headers=headers
110107
)
111108

109+
def get_response(self):
110+
"""
111+
Returns a response object.
112+
"""
113+
try:
114+
return self._conn.get_response()
115+
except HTTPUpgrade as e:
116+
# We upgraded via the HTTP Upgrade mechanism. We can just
117+
#go straight to the world of HTTP/2. Replace the backing object
118+
#and insert the socket into it.
119+
assert e.negotiated == H2C_PROTOCOL
120+
121+
self._conn = HTTP20Connection(
122+
self._host, self._port, **self._h2_kwargs
123+
)
124+
125+
#stream id 1 is used by the upgrade request and response
126+
self.next_stream_id += 2
127+
self._conn._sock = e.sock
128+
129+
# HTTP/2 preamble must be sent after receipt of a HTTP/1.1 101
130+
self._conn._send_preamble()
131+
132+
return e.resp
133+
112134
# Can anyone say 'proxy object pattern'?
113135
def __getattr__(self, name):
114136
return getattr(self._conn, name)

hyper/common/exceptions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class HTTPUpgrade(Exception):
5656
"""
5757
We upgraded to a new protocol via the HTTP Upgrade response.
5858
"""
59-
def __init__(self, negotiated, sock):
59+
def __init__(self, negotiated, sock, resp):
6060
super(HTTPUpgrade, self).__init__()
6161
self.negotiated = negotiated
6262
self.sock = sock
63+
self.resp = resp

hyper/http11/connection.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ..compat import bytes
2020

2121
from ..http20.connection import H2C_PROTOCOL
22+
from ..http20.response import HTTP20Response
2223
from ..packages.hyperframe.frame import SettingsFrame
2324

2425
# We prefer pycohttpparser to the pure-Python interpretation
@@ -138,9 +139,9 @@ def request(self, method, url, body=None, headers={}):
138139
headers[b'upgrade'] = H2C_PROTOCOL
139140

140141
#need to encode SETTINGS frame payload in Base64 and put into the HTTP-2 Settings header
141-
http2Settings = SettingsFrame(0)
142-
http2Settings.settings[SettingsFrame.INITIAL_WINDOW_SIZE] = 65535
143-
headers[b'HTTP2-Settings'] = base64.b64encode(http2Settings.serialize_body())
142+
http2_settings = SettingsFrame(0)
143+
http2_settings.settings[SettingsFrame.INITIAL_WINDOW_SIZE] = 65535
144+
headers[b'HTTP2-Settings'] = base64.b64encode(http2_settings.serialize_body())
144145

145146
# We may need extra headers.
146147
if body:
@@ -179,9 +180,10 @@ def get_response(self):
179180
self._sock.advance_buffer(response.consumed)
180181

181182
if(response.status == 101 and
182-
response.getheader('Connection') == 'Upgrade' and
183-
response.getheader('Upgrade') == H2C_PROTOCOL):
184-
raise HTTPUpgrade(proto, sock)
183+
b'upgrade' in headers['connection'] and bytes(H2C_PROTOCOL, 'utf-8') in headers['upgrade']):
184+
# HTTP/1.1 requests that are upgrade to HTTP/2.0 are responded to with steam id of 1
185+
headers[b':status'] = str(response.status)
186+
raise HTTPUpgrade(H2C_PROTOCOL, self._sock, HTTP20Response(headers, ))
185187

186188
return HTTP11Response(
187189
response.status,

hyper/http20/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ def putrequest(self, method, selector, **kwargs):
287287
# HTTP/2 specific. These are: ":method", ":scheme", ":authority" and
288288
# ":path". We can set all of these now.
289289
s.add_header(":method", method)
290-
s.add_header(":scheme", "https") # We only support HTTPS at this time.
290+
s.add_header(":scheme", "https" if self.secure else "http")
291291
s.add_header(":authority", self.host)
292292
s.add_header(":path", selector)
293293

0 commit comments

Comments
 (0)