Skip to content

Instantly share code, notes, and snippets.

@sethmlarson
Last active January 28, 2020 20:28
Show Gist options
  • Save sethmlarson/407bfdbffb3688479a5d5aa562315941 to your computer and use it in GitHub Desktop.
Save sethmlarson/407bfdbffb3688479a5d5aa562315941 to your computer and use it in GitHub Desktop.
Code that reproduces Yahoo's HTTP/2 issue.
"""
Code that reproduces Yahoo's HTTP/2 issue.
Requires you to run `python -m pip install h2` before executing.
Example output:
```
Testing 'google.com' with 'send_unknown_setting=False'...
Result: <ResponseReceived stream_id:1, headers:[(b':status', b'301'), (b'location', b...
Testing 'google.com' with 'send_unknown_setting=True'...
Result: <ResponseReceived stream_id:1, headers:[(b':status', b'301'), (b'location', b...
Testing 'yahoo.com' with 'send_unknown_setting=False'...
Result: <ResponseReceived stream_id:1, headers:[(b':status', b'301'), (b'date', b'Tue...
Testing 'yahoo.com' with 'send_unknown_setting=True'...
Result: <ConnectionTerminated error_code:ErrorCodes.PROTOCOL_ERROR, last_stream_id:0,...
```
"""
import socket
import ssl
import time
import h2.connection as h2_conn
import h2.events as h2_events
import h2.settings as h2_settings
def main():
# These all work fine.
func("google.com", send_unknown_setting=False)
func("google.com", send_unknown_setting=True)
func("yahoo.com", send_unknown_setting=False)
# This *does not* work fine.
func("yahoo.com", send_unknown_setting=True)
def func(host: str, send_unknown_setting: bool) -> None:
print(f"\nTesting '{host}' with 'send_unknown_setting={send_unknown_setting}'...")
ctx = ssl.create_default_context()
ctx.set_alpn_protocols(["h2"])
sock = socket.create_connection((host, 443))
sock = ctx.wrap_socket(sock, server_hostname=host)
# By default sends 'SETTINGS_ENABLE_CONNECT_PROTOCOL=0'
settings = h2_settings.Settings()
if not send_unknown_setting:
# Don't send 'SETTINGS_ENABLE_CONNECT_PROTOCOL'
settings._settings.pop(h2_settings.SettingCodes.ENABLE_CONNECT_PROTOCOL, None)
conn = h2_conn.H2Connection()
conn.local_settings = settings
conn.initiate_connection()
stream_id = conn.get_next_available_stream_id()
conn.send_headers(
stream_id,
[
(b":method", b"GET"),
(b":scheme", b"https"),
(b":authority", host.encode()),
(b":path", b"/"),
],
end_stream=True,
)
sock.sendall(conn.data_to_send())
received_response = False
while not received_response:
received_data = sock.recv(1024)
for event in conn.receive_data(received_data):
if isinstance(
event, (h2_events.ConnectionTerminated, h2_events.ResponseReceived)
):
print(f"Result: {str(event)[:77]}...")
received_response = True
time.sleep(0.1)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment