Skip to content

Commit

Permalink
[webtransport] Suppress benign error from StreamWriter.close() (#48351
Browse files Browse the repository at this point in the history
)

The error is logged when the client initially checks for connectivity,
which is unnecessarily confusing to users.

Needed for Chromium's python3.8 -> python3.11 upgrade.
  • Loading branch information
jonathan-j-lee committed Sep 26, 2024
1 parent f668923 commit 3429377
Showing 1 changed file with 28 additions and 3 deletions.
31 changes: 28 additions & 3 deletions tools/webtransport/h3/webtransport_h3_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# mypy: allow-subclassing-any, no-warn-return-any

import asyncio
import contextlib
import logging
import os
import ssl
Expand All @@ -9,17 +10,21 @@
import traceback
from enum import IntEnum
from urllib.parse import urlparse
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple, cast

# TODO(bashi): Remove import check suppressions once aioquic dependency is resolved.
from aioquic.buffer import Buffer # type: ignore
from aioquic.asyncio import QuicConnectionProtocol, serve # type: ignore
from aioquic.asyncio.client import connect # type: ignore
from aioquic.asyncio.protocol import QuicStreamAdapter # type: ignore
from aioquic.h3.connection import H3_ALPN, FrameType, H3Connection, ProtocolError, SettingsError # type: ignore
from aioquic.h3.events import H3Event, HeadersReceived, WebTransportStreamDataReceived, DatagramReceived, DataReceived # type: ignore
from aioquic.quic.configuration import QuicConfiguration # type: ignore
from aioquic.quic.connection import logger as quic_connection_logger # type: ignore
from aioquic.quic.connection import stream_is_unidirectional
from aioquic.quic.connection import (
stream_is_client_initiated,
stream_is_unidirectional,
)
from aioquic.quic.events import QuicEvent, ProtocolNegotiated, ConnectionTerminated, StreamReset # type: ignore
from aioquic.tls import SessionTicket # type: ignore

Expand Down Expand Up @@ -602,12 +607,32 @@ async def _connect_server_with_timeout(host: str, port: int, timeout: float) ->
return True


def _close_unusable_writer(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
# Starting in python3.11, `StreamWriter.__del__` implicitly `close()`s
# itself [0], if it has not done so already. Because aioquic sometimes
# models a unidirectional stream with a bidirectional transport [1], the
# `writer` here for a server -> client stream may log a benign but
# scary-looking exception when it's GC'ed and unsuccessfully writes EOF.
#
# For the purpose of checking connectivity, work around this for now by
# preemptively closing such streams and suppressing the resulting
# exceptions.
#
# [0]: https://github.com/python/cpython/blob/3.11/Lib/asyncio/streams.py#L413
# [1]: https://github.com/aiortc/aioquic/blob/1.2.0/src/aioquic/asyncio/protocol.py#L241
stream_id = cast(QuicStreamAdapter, writer.transport).stream_id
if stream_is_unidirectional(stream_id) and not stream_is_client_initiated(stream_id):
with contextlib.suppress(ValueError):
writer.close()


async def _connect_to_server(host: str, port: int) -> None:
configuration = QuicConfiguration(
alpn_protocols=H3_ALPN,
is_client=True,
verify_mode=ssl.CERT_NONE,
)

async with connect(host, port, configuration=configuration) as protocol:
async with connect(host, port, configuration=configuration,
stream_handler=_close_unusable_writer) as protocol:
await protocol.ping()

0 comments on commit 3429377

Please sign in to comment.