def run(url: str) -> None: # parse URL parsed = urlparse(url) assert parsed.scheme == "https", "Only HTTPS URLs are supported." if ":" in parsed.netloc: server_name, port_str = parsed.netloc.split(":") port = int(port_str) else: server_name = parsed.netloc port = 443 # prepare socket server_addr = (socket.gethostbyname(server_name), port) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # prepare QUIC connection quic = QuicConnection(configuration=QuicConfiguration( alpn_protocols=["h3-20"], is_client=True, secrets_log_file=open("/tmp/ssl.log", "w"), server_name=server_name, )) quic.connect(server_addr, now=time.time()) # send request http = H3Connection(quic) stream_id = quic.get_next_available_stream_id() http.send_headers( stream_id=stream_id, headers=[ (b":method", b"GET"), (b":scheme", parsed.scheme.encode("utf8")), (b":authority", parsed.netloc.encode("utf8")), (b":path", parsed.path.encode("utf8")), ], ) http.send_data(stream_id=stream_id, data=b"", end_stream=True) for data, addr in quic.datagrams_to_send(now=time.time()): sock.sendto(data, addr) # handle events stream_ended = False while not stream_ended: data, addr = sock.recvfrom(2048) quic.receive_datagram(data, addr, now=time.time()) for event in http.handle_events(): print(event) if isinstance(event, (DataReceived, ResponseReceived)): stream_ended = event.stream_ended for data, addr in quic.datagrams_to_send(now=time.time()): sock.sendto(data, addr)
def _consume_events(self, connection: QuicConnection) -> None: # process events event = connection.next_event() while event is not None: if isinstance(event, aioquic.events.HandshakeCompleted): if event.alpn_protocol == "h3-20": self._http[connection] = H3Connection(connection) elif event.alpn_protocol == "hq-20": self._http[connection] = H0Connection(connection) elif isinstance(event, aioquic.events.ConnectionIdIssued): self._connections[event.connection_id] = connection elif isinstance(event, aioquic.events.ConnectionIdRetired): assert self._connections[event.connection_id] == connection del self._connections[event.connection_id] # pass event to the HTTP layer http = self._http.get(connection) if http is not None: for http_event in http.handle_event(event): handle_http_event(http, http_event) event = connection.next_event() # send datagrams for data, addr in connection.datagrams_to_send(now=self._loop.time()): self._transport.sendto(data, addr) # re-arm timer """