from typing import Dict, List from aioquic.h3.events import DataReceived, H3Event, Headers, HeadersReceived from aioquic.quic.connection import QuicConnection from aioquic.quic.events import QuicEvent, StreamDataReceived H0_ALPN = ["hq-29", "hq-28", "hq-27"] class H0Connection: """ An HTTP/0.9 connection object. """ def __init__(self, quic: QuicConnection): self._buffer: Dict[int, bytes] = {} self._headers_received: Dict[int, bool] = {} self._is_client = quic.configuration.is_client self._quic = quic def handle_event(self, event: QuicEvent) -> List[H3Event]: http_events: List[H3Event] = [] if isinstance(event, StreamDataReceived) and (event.stream_id % 4) == 0: data = self._buffer.pop(event.stream_id, b"") + event.data if not self._headers_received.get(event.stream_id, False): if self._is_client: http_events.append( HeadersReceived( headers=[], stream_ended=False, stream_id=event.stream_id ) ) elif data.endswith(b"\r\n") or event.end_stream: method, path = data.rstrip().split(b" ", 1) http_events.append( HeadersReceived( headers=[(b":method", method), (b":path", path)], stream_ended=False, stream_id=event.stream_id, ) ) data = b"" else: # incomplete request, stash the data self._buffer[event.stream_id] = data return http_events self._headers_received[event.stream_id] = True http_events.append( DataReceived( data=data, stream_ended=event.end_stream, stream_id=event.stream_id ) ) return http_events def send_data(self, stream_id: int, data: bytes, end_stream: bool) -> None: self._quic.send_stream_data(stream_id, data, end_stream) def send_headers( self, stream_id: int, headers: Headers, end_stream: bool = False ) -> None: if self._is_client: headers_dict = dict(headers) data = headers_dict[b":method"] + b" " + headers_dict[b":path"] + b"\r\n" else: data = b"" self._quic.send_stream_data(stream_id, data, end_stream)