Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -6,30 +6,13 @@ import sys
|
|||
import traceback
|
||||
import warnings
|
||||
from collections import OrderedDict, defaultdict, deque
|
||||
from collections.abc import Awaitable, Callable, Iterator, Sequence
|
||||
from contextlib import suppress
|
||||
from http import HTTPStatus
|
||||
from itertools import chain, cycle, islice
|
||||
from time import monotonic
|
||||
from types import TracebackType
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable,
|
||||
DefaultDict,
|
||||
Deque,
|
||||
Dict,
|
||||
Iterator,
|
||||
List,
|
||||
Literal,
|
||||
Optional,
|
||||
Sequence,
|
||||
Set,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
|
||||
|
||||
import aiohappyeyeballs
|
||||
from aiohappyeyeballs import AddrInfoType, SocketFactoryType
|
||||
|
|
@ -44,6 +27,7 @@ from .client_exceptions import (
|
|||
ClientConnectorSSLError,
|
||||
ClientHttpProxyError,
|
||||
ClientProxyConnectionError,
|
||||
InvalidUrlClientError,
|
||||
ServerFingerprintMismatch,
|
||||
UnixClientConnectorError,
|
||||
cert_errors,
|
||||
|
|
@ -54,6 +38,7 @@ from .client_reqrep import ClientRequest, Fingerprint, _merge_ssl_params
|
|||
from .helpers import (
|
||||
_SENTINEL,
|
||||
ceil_timeout,
|
||||
is_canonical_ipv4_address,
|
||||
is_ip_address,
|
||||
noop,
|
||||
sentinel,
|
||||
|
|
@ -92,9 +77,9 @@ NEEDS_CLEANUP_CLOSED = (3, 13, 0) <= sys.version_info < (
|
|||
3,
|
||||
13,
|
||||
1,
|
||||
) or sys.version_info < (3, 12, 7)
|
||||
) or sys.version_info < (3, 12, 8)
|
||||
# Cleanup closed is no longer needed after https://github.com/python/cpython/pull/118960
|
||||
# which first appeared in Python 3.12.7 and 3.13.1
|
||||
# which first appeared in Python 3.12.8 and 3.13.1
|
||||
|
||||
|
||||
__all__ = (
|
||||
|
|
@ -133,7 +118,7 @@ class _DeprecationWaiter:
|
|||
)
|
||||
|
||||
|
||||
async def _wait_for_close(waiters: List[Awaitable[object]]) -> None:
|
||||
async def _wait_for_close(waiters: list[Awaitable[object]]) -> None:
|
||||
"""Wait for all waiters to finish closing."""
|
||||
results = await asyncio.gather(*waiters, return_exceptions=True)
|
||||
for res in results:
|
||||
|
|
@ -155,8 +140,8 @@ class Connection:
|
|||
self._key = key
|
||||
self._connector = connector
|
||||
self._loop = loop
|
||||
self._protocol: Optional[ResponseHandler] = protocol
|
||||
self._callbacks: List[Callable[[], None]] = []
|
||||
self._protocol: ResponseHandler | None = protocol
|
||||
self._callbacks: list[Callable[[], None]] = []
|
||||
|
||||
if loop.get_debug():
|
||||
self._source_traceback = traceback.extract_stack(sys._getframe(1))
|
||||
|
|
@ -190,13 +175,13 @@ class Connection:
|
|||
return self._loop
|
||||
|
||||
@property
|
||||
def transport(self) -> Optional[asyncio.Transport]:
|
||||
def transport(self) -> asyncio.Transport | None:
|
||||
if self._protocol is None:
|
||||
return None
|
||||
return self._protocol.transport
|
||||
|
||||
@property
|
||||
def protocol(self) -> Optional[ResponseHandler]:
|
||||
def protocol(self) -> ResponseHandler | None:
|
||||
return self._protocol
|
||||
|
||||
def add_callback(self, callback: Callable[[], None]) -> None:
|
||||
|
|
@ -254,7 +239,7 @@ class _TransportPlaceholder:
|
|||
|
||||
__slots__ = ("closed", "transport")
|
||||
|
||||
def __init__(self, closed_future: asyncio.Future[Optional[Exception]]) -> None:
|
||||
def __init__(self, closed_future: asyncio.Future[Exception | None]) -> None:
|
||||
"""Initialize a placeholder for a transport."""
|
||||
self.closed = closed_future
|
||||
self.transport = None
|
||||
|
|
@ -292,12 +277,12 @@ class BaseConnector:
|
|||
def __init__(
|
||||
self,
|
||||
*,
|
||||
keepalive_timeout: Union[object, None, float] = sentinel,
|
||||
keepalive_timeout: object | None | float = sentinel,
|
||||
force_close: bool = False,
|
||||
limit: int = 100,
|
||||
limit_per_host: int = 0,
|
||||
enable_cleanup_closed: bool = False,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
timeout_ceil_threshold: float = 5,
|
||||
) -> None:
|
||||
|
||||
|
|
@ -320,13 +305,13 @@ class BaseConnector:
|
|||
# Connection pool of reusable connections.
|
||||
# We use a deque to store connections because it has O(1) popleft()
|
||||
# and O(1) append() operations to implement a FIFO queue.
|
||||
self._conns: DefaultDict[
|
||||
ConnectionKey, Deque[Tuple[ResponseHandler, float]]
|
||||
self._conns: defaultdict[
|
||||
ConnectionKey, deque[tuple[ResponseHandler, float]]
|
||||
] = defaultdict(deque)
|
||||
self._limit = limit
|
||||
self._limit_per_host = limit_per_host
|
||||
self._acquired: Set[ResponseHandler] = set()
|
||||
self._acquired_per_host: DefaultDict[ConnectionKey, Set[ResponseHandler]] = (
|
||||
self._acquired: set[ResponseHandler] = set()
|
||||
self._acquired_per_host: defaultdict[ConnectionKey, set[ResponseHandler]] = (
|
||||
defaultdict(set)
|
||||
)
|
||||
self._keepalive_timeout = cast(float, keepalive_timeout)
|
||||
|
|
@ -335,7 +320,7 @@ class BaseConnector:
|
|||
# {host_key: FIFO list of waiters}
|
||||
# The FIFO is implemented with an OrderedDict with None keys because
|
||||
# python does not have an ordered set.
|
||||
self._waiters: DefaultDict[
|
||||
self._waiters: defaultdict[
|
||||
ConnectionKey, OrderedDict[asyncio.Future[None], None]
|
||||
] = defaultdict(OrderedDict)
|
||||
|
||||
|
|
@ -343,10 +328,10 @@ class BaseConnector:
|
|||
self._factory = functools.partial(ResponseHandler, loop=loop)
|
||||
|
||||
# start keep-alive connection cleanup task
|
||||
self._cleanup_handle: Optional[asyncio.TimerHandle] = None
|
||||
self._cleanup_handle: asyncio.TimerHandle | None = None
|
||||
|
||||
# start cleanup closed transports task
|
||||
self._cleanup_closed_handle: Optional[asyncio.TimerHandle] = None
|
||||
self._cleanup_closed_handle: asyncio.TimerHandle | None = None
|
||||
|
||||
if enable_cleanup_closed and not NEEDS_CLEANUP_CLOSED:
|
||||
warnings.warn(
|
||||
|
|
@ -359,8 +344,8 @@ class BaseConnector:
|
|||
enable_cleanup_closed = False
|
||||
|
||||
self._cleanup_closed_disabled = not enable_cleanup_closed
|
||||
self._cleanup_closed_transports: List[Optional[asyncio.Transport]] = []
|
||||
self._placeholder_future: asyncio.Future[Optional[Exception]] = (
|
||||
self._cleanup_closed_transports: list[asyncio.Transport | None] = []
|
||||
self._placeholder_future: asyncio.Future[Exception | None] = (
|
||||
loop.create_future()
|
||||
)
|
||||
self._placeholder_future.set_result(None)
|
||||
|
|
@ -403,9 +388,9 @@ class BaseConnector:
|
|||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]] = None,
|
||||
exc_value: Optional[BaseException] = None,
|
||||
exc_traceback: Optional[TracebackType] = None,
|
||||
exc_type: type[BaseException] | None = None,
|
||||
exc_value: BaseException | None = None,
|
||||
exc_traceback: TracebackType | None = None,
|
||||
) -> None:
|
||||
await self.close()
|
||||
|
||||
|
|
@ -447,7 +432,7 @@ class BaseConnector:
|
|||
connections = defaultdict(deque)
|
||||
deadline = now - timeout
|
||||
for key, conns in self._conns.items():
|
||||
alive: Deque[Tuple[ResponseHandler, float]] = deque()
|
||||
alive: deque[tuple[ResponseHandler, float]] = deque()
|
||||
for proto, use_time in conns:
|
||||
if proto.is_connected() and use_time - deadline >= 0:
|
||||
alive.append((proto, use_time))
|
||||
|
|
@ -514,8 +499,8 @@ class BaseConnector:
|
|||
task = self._loop.create_task(coro)
|
||||
return _DeprecationWaiter(task)
|
||||
|
||||
def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]:
|
||||
waiters: List[Awaitable[object]] = []
|
||||
def _close(self, *, abort_ssl: bool = False) -> list[Awaitable[object]]:
|
||||
waiters: list[Awaitable[object]] = []
|
||||
|
||||
if self._closed:
|
||||
return waiters
|
||||
|
|
@ -615,7 +600,7 @@ class BaseConnector:
|
|||
"""Set Proxy-Authorization header for non-SSL proxy requests and builds the proxy request for SSL proxy requests."""
|
||||
url = req.proxy
|
||||
assert url is not None
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
if req.proxy_headers is not None:
|
||||
headers = req.proxy_headers # type: ignore[assignment]
|
||||
headers[hdrs.HOST] = req.headers[hdrs.HOST]
|
||||
|
|
@ -636,7 +621,7 @@ class BaseConnector:
|
|||
return proxy_req
|
||||
|
||||
async def connect(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> Connection:
|
||||
"""Get from pool or create new connection."""
|
||||
key = req.connection_key
|
||||
|
|
@ -695,7 +680,7 @@ class BaseConnector:
|
|||
return Connection(self, key, proto, self._loop)
|
||||
|
||||
async def _wait_for_available_connection(
|
||||
self, key: "ConnectionKey", traces: List["Trace"]
|
||||
self, key: "ConnectionKey", traces: list["Trace"]
|
||||
) -> None:
|
||||
"""Wait for an available connection slot."""
|
||||
# We loop here because there is a race between
|
||||
|
|
@ -737,8 +722,8 @@ class BaseConnector:
|
|||
attempts += 1
|
||||
|
||||
async def _get(
|
||||
self, key: "ConnectionKey", traces: List["Trace"]
|
||||
) -> Optional[Connection]:
|
||||
self, key: "ConnectionKey", traces: list["Trace"]
|
||||
) -> Connection | None:
|
||||
"""Get next reusable connection for the key or None.
|
||||
|
||||
The connection will be marked as acquired.
|
||||
|
|
@ -850,44 +835,53 @@ class BaseConnector:
|
|||
)
|
||||
|
||||
async def _create_connection(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> ResponseHandler:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class _DNSCacheTable:
|
||||
def __init__(self, ttl: Optional[float] = None) -> None:
|
||||
self._addrs_rr: Dict[Tuple[str, int], Tuple[Iterator[ResolveResult], int]] = {}
|
||||
self._timestamps: Dict[Tuple[str, int], float] = {}
|
||||
def __init__(self, ttl: float | None = None, max_size: int = 1000) -> None:
|
||||
self._addrs_rr: OrderedDict[
|
||||
tuple[str, int], tuple[Iterator[ResolveResult], int]
|
||||
] = OrderedDict()
|
||||
self._timestamps: dict[tuple[str, int], float] = {}
|
||||
self._ttl = ttl
|
||||
self._max_size = max_size
|
||||
|
||||
def __contains__(self, host: object) -> bool:
|
||||
return host in self._addrs_rr
|
||||
|
||||
def add(self, key: Tuple[str, int], addrs: List[ResolveResult]) -> None:
|
||||
def add(self, key: tuple[str, int], addrs: list[ResolveResult]) -> None:
|
||||
if key in self._addrs_rr:
|
||||
self._addrs_rr.move_to_end(key)
|
||||
|
||||
self._addrs_rr[key] = (cycle(addrs), len(addrs))
|
||||
|
||||
if self._ttl is not None:
|
||||
self._timestamps[key] = monotonic()
|
||||
|
||||
def remove(self, key: Tuple[str, int]) -> None:
|
||||
self._addrs_rr.pop(key, None)
|
||||
if len(self._addrs_rr) > self._max_size:
|
||||
oldest_key, _ = self._addrs_rr.popitem(last=False)
|
||||
self._timestamps.pop(oldest_key, None)
|
||||
|
||||
if self._ttl is not None:
|
||||
self._timestamps.pop(key, None)
|
||||
def remove(self, key: tuple[str, int]) -> None:
|
||||
self._addrs_rr.pop(key, None)
|
||||
self._timestamps.pop(key, None)
|
||||
|
||||
def clear(self) -> None:
|
||||
self._addrs_rr.clear()
|
||||
self._timestamps.clear()
|
||||
|
||||
def next_addrs(self, key: Tuple[str, int]) -> List[ResolveResult]:
|
||||
def next_addrs(self, key: tuple[str, int]) -> list[ResolveResult]:
|
||||
loop, length = self._addrs_rr[key]
|
||||
addrs = list(islice(loop, length))
|
||||
# Consume one more element to shift internal state of `cycle`
|
||||
next(loop)
|
||||
self._addrs_rr.move_to_end(key)
|
||||
return addrs
|
||||
|
||||
def expired(self, key: Tuple[str, int]) -> bool:
|
||||
def expired(self, key: tuple[str, int]) -> bool:
|
||||
if self._ttl is None:
|
||||
return False
|
||||
|
||||
|
|
@ -970,25 +964,26 @@ class TCPConnector(BaseConnector):
|
|||
self,
|
||||
*,
|
||||
verify_ssl: bool = True,
|
||||
fingerprint: Optional[bytes] = None,
|
||||
fingerprint: bytes | None = None,
|
||||
use_dns_cache: bool = True,
|
||||
ttl_dns_cache: Optional[int] = 10,
|
||||
ttl_dns_cache: int | None = 10,
|
||||
dns_cache_max_size: int = 1000,
|
||||
family: socket.AddressFamily = socket.AddressFamily.AF_UNSPEC,
|
||||
ssl_context: Optional[SSLContext] = None,
|
||||
ssl: Union[bool, Fingerprint, SSLContext] = True,
|
||||
local_addr: Optional[Tuple[str, int]] = None,
|
||||
resolver: Optional[AbstractResolver] = None,
|
||||
keepalive_timeout: Union[None, float, object] = sentinel,
|
||||
ssl_context: SSLContext | None = None,
|
||||
ssl: bool | Fingerprint | SSLContext = True,
|
||||
local_addr: tuple[str, int] | None = None,
|
||||
resolver: AbstractResolver | None = None,
|
||||
keepalive_timeout: None | float | object = sentinel,
|
||||
force_close: bool = False,
|
||||
limit: int = 100,
|
||||
limit_per_host: int = 0,
|
||||
enable_cleanup_closed: bool = False,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
timeout_ceil_threshold: float = 5,
|
||||
happy_eyeballs_delay: Optional[float] = 0.25,
|
||||
interleave: Optional[int] = None,
|
||||
socket_factory: Optional[SocketFactoryType] = None,
|
||||
ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel,
|
||||
happy_eyeballs_delay: float | None = 0.25,
|
||||
interleave: int | None = None,
|
||||
socket_factory: SocketFactoryType | None = None,
|
||||
ssl_shutdown_timeout: _SENTINEL | None | float = sentinel,
|
||||
):
|
||||
super().__init__(
|
||||
keepalive_timeout=keepalive_timeout,
|
||||
|
|
@ -1011,17 +1006,19 @@ class TCPConnector(BaseConnector):
|
|||
self._resolver_owner = False
|
||||
|
||||
self._use_dns_cache = use_dns_cache
|
||||
self._cached_hosts = _DNSCacheTable(ttl=ttl_dns_cache)
|
||||
self._throttle_dns_futures: Dict[
|
||||
Tuple[str, int], Set["asyncio.Future[None]"]
|
||||
] = {}
|
||||
self._cached_hosts = _DNSCacheTable(
|
||||
ttl=ttl_dns_cache, max_size=dns_cache_max_size
|
||||
)
|
||||
self._throttle_dns_futures: dict[tuple[str, int], set[asyncio.Future[None]]] = (
|
||||
{}
|
||||
)
|
||||
self._family = family
|
||||
self._local_addr_infos = aiohappyeyeballs.addr_to_addr_infos(local_addr)
|
||||
self._happy_eyeballs_delay = happy_eyeballs_delay
|
||||
self._interleave = interleave
|
||||
self._resolve_host_tasks: Set["asyncio.Task[List[ResolveResult]]"] = set()
|
||||
self._resolve_host_tasks: set[asyncio.Task[list[ResolveResult]]] = set()
|
||||
self._socket_factory = socket_factory
|
||||
self._ssl_shutdown_timeout: Optional[float]
|
||||
self._ssl_shutdown_timeout: float | None
|
||||
# Handle ssl_shutdown_timeout with warning for Python < 3.11
|
||||
if ssl_shutdown_timeout is sentinel:
|
||||
self._ssl_shutdown_timeout = 0
|
||||
|
|
@ -1045,7 +1042,7 @@ class TCPConnector(BaseConnector):
|
|||
)
|
||||
self._ssl_shutdown_timeout = ssl_shutdown_timeout
|
||||
|
||||
def _close(self, *, abort_ssl: bool = False) -> List[Awaitable[object]]:
|
||||
def _close(self, *, abort_ssl: bool = False) -> list[Awaitable[object]]:
|
||||
"""Close all ongoing DNS calls."""
|
||||
for fut in chain.from_iterable(self._throttle_dns_futures.values()):
|
||||
fut.cancel()
|
||||
|
|
@ -1068,10 +1065,10 @@ class TCPConnector(BaseConnector):
|
|||
- If ssl_shutdown_timeout=0: connections are aborted
|
||||
- If ssl_shutdown_timeout>0: graceful shutdown is performed
|
||||
"""
|
||||
if self._resolver_owner:
|
||||
await self._resolver.close()
|
||||
# Use abort_ssl param if explicitly set, otherwise use ssl_shutdown_timeout default
|
||||
await super().close(abort_ssl=abort_ssl or self._ssl_shutdown_timeout == 0)
|
||||
if self._resolver_owner:
|
||||
await self._resolver.close()
|
||||
|
||||
@property
|
||||
def family(self) -> int:
|
||||
|
|
@ -1083,9 +1080,7 @@ class TCPConnector(BaseConnector):
|
|||
"""True if local DNS caching is enabled."""
|
||||
return self._use_dns_cache
|
||||
|
||||
def clear_dns_cache(
|
||||
self, host: Optional[str] = None, port: Optional[int] = None
|
||||
) -> None:
|
||||
def clear_dns_cache(self, host: str | None = None, port: int | None = None) -> None:
|
||||
"""Remove specified host/port or clear all dns local cache."""
|
||||
if host is not None and port is not None:
|
||||
self._cached_hosts.remove((host, port))
|
||||
|
|
@ -1095,10 +1090,15 @@ class TCPConnector(BaseConnector):
|
|||
self._cached_hosts.clear()
|
||||
|
||||
async def _resolve_host(
|
||||
self, host: str, port: int, traces: Optional[Sequence["Trace"]] = None
|
||||
) -> List[ResolveResult]:
|
||||
self, host: str, port: int, traces: Sequence["Trace"] | None = None
|
||||
) -> list[ResolveResult]:
|
||||
"""Resolve host and return list of addresses."""
|
||||
if is_ip_address(host):
|
||||
# Reject legacy numeric IPv4 forms (e.g. 2130706433, 127.1) that
|
||||
# socket would map onto an address, slipping past a connector-level
|
||||
# policy that only sees the raw host.
|
||||
if ":" not in host and not is_canonical_ipv4_address(host):
|
||||
raise InvalidUrlClientError(host, "is not a canonical IPv4 address")
|
||||
return [
|
||||
{
|
||||
"hostname": host,
|
||||
|
|
@ -1116,6 +1116,9 @@ class TCPConnector(BaseConnector):
|
|||
for trace in traces:
|
||||
await trace.send_dns_resolvehost_start(host)
|
||||
|
||||
if self._closed:
|
||||
raise ClientConnectionError("Connector is closed")
|
||||
|
||||
res = await self._resolver.resolve(host, port, family=self._family)
|
||||
|
||||
if traces:
|
||||
|
|
@ -1134,7 +1137,7 @@ class TCPConnector(BaseConnector):
|
|||
await trace.send_dns_cache_hit(host)
|
||||
return result
|
||||
|
||||
futures: Set["asyncio.Future[None]"]
|
||||
futures: set[asyncio.Future[None]]
|
||||
#
|
||||
# If multiple connectors are resolving the same host, we wait
|
||||
# for the first one to resolve and then use the result for all of them.
|
||||
|
|
@ -1178,7 +1181,7 @@ class TCPConnector(BaseConnector):
|
|||
return await asyncio.shield(resolved_host_task)
|
||||
except asyncio.CancelledError:
|
||||
|
||||
def drop_exception(fut: "asyncio.Future[List[ResolveResult]]") -> None:
|
||||
def drop_exception(fut: "asyncio.Future[list[ResolveResult]]") -> None:
|
||||
with suppress(Exception, asyncio.CancelledError):
|
||||
fut.result()
|
||||
|
||||
|
|
@ -1187,12 +1190,12 @@ class TCPConnector(BaseConnector):
|
|||
|
||||
async def _resolve_host_with_throttle(
|
||||
self,
|
||||
key: Tuple[str, int],
|
||||
key: tuple[str, int],
|
||||
host: str,
|
||||
port: int,
|
||||
futures: Set["asyncio.Future[None]"],
|
||||
traces: Optional[Sequence["Trace"]],
|
||||
) -> List[ResolveResult]:
|
||||
futures: set["asyncio.Future[None]"],
|
||||
traces: Sequence["Trace"] | None,
|
||||
) -> list[ResolveResult]:
|
||||
"""Resolve host and set result for all waiters.
|
||||
|
||||
This method must be run in a task and shielded from cancellation
|
||||
|
|
@ -1227,7 +1230,7 @@ class TCPConnector(BaseConnector):
|
|||
return self._cached_hosts.next_addrs(key)
|
||||
|
||||
async def _create_connection(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> ResponseHandler:
|
||||
"""Create connection.
|
||||
|
||||
|
|
@ -1240,7 +1243,7 @@ class TCPConnector(BaseConnector):
|
|||
|
||||
return proto
|
||||
|
||||
def _get_ssl_context(self, req: ClientRequest) -> Optional[SSLContext]:
|
||||
def _get_ssl_context(self, req: ClientRequest) -> SSLContext | None:
|
||||
"""Logic to get the correct SSL context
|
||||
|
||||
0. if req.ssl is false, return None
|
||||
|
|
@ -1285,12 +1288,12 @@ class TCPConnector(BaseConnector):
|
|||
async def _wrap_create_connection(
|
||||
self,
|
||||
*args: Any,
|
||||
addr_infos: List[AddrInfoType],
|
||||
addr_infos: list[AddrInfoType],
|
||||
req: ClientRequest,
|
||||
timeout: "ClientTimeout",
|
||||
client_error: Type[Exception] = ClientConnectorError,
|
||||
client_error: type[Exception] = ClientConnectorError,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[asyncio.Transport, ResponseHandler]:
|
||||
) -> tuple[asyncio.Transport, ResponseHandler]:
|
||||
try:
|
||||
async with ceil_timeout(
|
||||
timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
|
||||
|
|
@ -1325,9 +1328,9 @@ class TCPConnector(BaseConnector):
|
|||
*args: Any,
|
||||
req: ClientRequest,
|
||||
timeout: "ClientTimeout",
|
||||
client_error: Type[Exception] = ClientConnectorError,
|
||||
client_error: type[Exception] = ClientConnectorError,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[asyncio.Transport, ResponseHandler]:
|
||||
) -> tuple[asyncio.Transport, ResponseHandler]:
|
||||
try:
|
||||
async with ceil_timeout(
|
||||
timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
|
||||
|
|
@ -1394,6 +1397,12 @@ class TCPConnector(BaseConnector):
|
|||
if req.request_info.url.scheme != "https":
|
||||
return
|
||||
|
||||
# TLS-in-TLS only applies when the proxy itself is HTTPS.
|
||||
# When the proxy is HTTP, start_tls upgrades a plain TCP connection,
|
||||
# which is standard TLS and works on all event loops and Python versions.
|
||||
if req.proxy is None or req.proxy.scheme != "https":
|
||||
return
|
||||
|
||||
# Check if uvloop is being used, which supports TLS in TLS,
|
||||
# otherwise assume that asyncio's native transport is being used.
|
||||
if type(underlying_transport).__module__.startswith("uvloop"):
|
||||
|
|
@ -1433,8 +1442,8 @@ class TCPConnector(BaseConnector):
|
|||
underlying_transport: asyncio.Transport,
|
||||
req: ClientRequest,
|
||||
timeout: "ClientTimeout",
|
||||
client_error: Type[Exception] = ClientConnectorError,
|
||||
) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
|
||||
client_error: type[Exception] = ClientConnectorError,
|
||||
) -> tuple[asyncio.BaseTransport, ResponseHandler]:
|
||||
"""Wrap the raw TCP transport with TLS."""
|
||||
tls_proto = self._factory() # Create a brand new proto for TLS
|
||||
sslcontext = self._get_ssl_context(req)
|
||||
|
|
@ -1455,7 +1464,7 @@ class TCPConnector(BaseConnector):
|
|||
tls_proto,
|
||||
sslcontext,
|
||||
server_hostname=req.server_hostname or req.host,
|
||||
ssl_handshake_timeout=timeout.total,
|
||||
ssl_handshake_timeout=timeout.total or None,
|
||||
ssl_shutdown_timeout=self._ssl_shutdown_timeout,
|
||||
)
|
||||
else:
|
||||
|
|
@ -1464,7 +1473,7 @@ class TCPConnector(BaseConnector):
|
|||
tls_proto,
|
||||
sslcontext,
|
||||
server_hostname=req.server_hostname or req.host,
|
||||
ssl_handshake_timeout=timeout.total,
|
||||
ssl_handshake_timeout=timeout.total or None,
|
||||
)
|
||||
except BaseException:
|
||||
# We need to close the underlying transport since
|
||||
|
|
@ -1515,14 +1524,14 @@ class TCPConnector(BaseConnector):
|
|||
return tls_transport, tls_proto
|
||||
|
||||
def _convert_hosts_to_addr_infos(
|
||||
self, hosts: List[ResolveResult]
|
||||
) -> List[AddrInfoType]:
|
||||
self, hosts: list[ResolveResult]
|
||||
) -> list[AddrInfoType]:
|
||||
"""Converts the list of hosts to a list of addr_infos.
|
||||
|
||||
The list of hosts is the result of a DNS lookup. The list of
|
||||
addr_infos is the result of a call to `socket.getaddrinfo()`.
|
||||
"""
|
||||
addr_infos: List[AddrInfoType] = []
|
||||
addr_infos: list[AddrInfoType] = []
|
||||
for hinfo in hosts:
|
||||
host = hinfo["host"]
|
||||
is_ipv6 = ":" in host
|
||||
|
|
@ -1538,11 +1547,11 @@ class TCPConnector(BaseConnector):
|
|||
async def _create_direct_connection(
|
||||
self,
|
||||
req: ClientRequest,
|
||||
traces: List["Trace"],
|
||||
traces: list["Trace"],
|
||||
timeout: "ClientTimeout",
|
||||
*,
|
||||
client_error: Type[Exception] = ClientConnectorError,
|
||||
) -> Tuple[asyncio.Transport, ResponseHandler]:
|
||||
client_error: type[Exception] = ClientConnectorError,
|
||||
) -> tuple[asyncio.Transport, ResponseHandler]:
|
||||
sslcontext = self._get_ssl_context(req)
|
||||
fingerprint = self._get_fingerprint(req)
|
||||
|
||||
|
|
@ -1567,7 +1576,7 @@ class TCPConnector(BaseConnector):
|
|||
# it is problem of resolving proxy ip itself
|
||||
raise ClientConnectorDNSError(req.connection_key, exc) from exc
|
||||
|
||||
last_exc: Optional[Exception] = None
|
||||
last_exc: Exception | None = None
|
||||
addr_infos = self._convert_hosts_to_addr_infos(hosts)
|
||||
while addr_infos:
|
||||
# Strip trailing dots, certificates contain FQDN without dots.
|
||||
|
|
@ -1611,8 +1620,8 @@ class TCPConnector(BaseConnector):
|
|||
raise last_exc
|
||||
|
||||
async def _create_proxy_connection(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
) -> Tuple[asyncio.BaseTransport, ResponseHandler]:
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> tuple[asyncio.BaseTransport, ResponseHandler]:
|
||||
self._fail_on_no_start_tls(req)
|
||||
runtime_has_start_tls = self._loop_supports_start_tls()
|
||||
proxy_req = self._update_proxy_auth_header_and_build_proxy_req(req)
|
||||
|
|
@ -1733,10 +1742,10 @@ class UnixConnector(BaseConnector):
|
|||
self,
|
||||
path: str,
|
||||
force_close: bool = False,
|
||||
keepalive_timeout: Union[object, float, None] = sentinel,
|
||||
keepalive_timeout: object | float | None = sentinel,
|
||||
limit: int = 100,
|
||||
limit_per_host: int = 0,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
force_close=force_close,
|
||||
|
|
@ -1753,7 +1762,7 @@ class UnixConnector(BaseConnector):
|
|||
return self._path
|
||||
|
||||
async def _create_connection(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> ResponseHandler:
|
||||
try:
|
||||
async with ceil_timeout(
|
||||
|
|
@ -1791,10 +1800,10 @@ class NamedPipeConnector(BaseConnector):
|
|||
self,
|
||||
path: str,
|
||||
force_close: bool = False,
|
||||
keepalive_timeout: Union[object, float, None] = sentinel,
|
||||
keepalive_timeout: object | float | None = sentinel,
|
||||
limit: int = 100,
|
||||
limit_per_host: int = 0,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None,
|
||||
loop: asyncio.AbstractEventLoop | None = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
force_close=force_close,
|
||||
|
|
@ -1818,7 +1827,7 @@ class NamedPipeConnector(BaseConnector):
|
|||
return self._path
|
||||
|
||||
async def _create_connection(
|
||||
self, req: ClientRequest, traces: List["Trace"], timeout: "ClientTimeout"
|
||||
self, req: ClientRequest, traces: list["Trace"], timeout: "ClientTimeout"
|
||||
) -> ResponseHandler:
|
||||
try:
|
||||
async with ceil_timeout(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue