Given (host, port) and PoolOptions, return a configured AsyncNetworkingInterface. Can raise socket.error, ConnectionFailure, or _CertificateError. Sets protocol's SSL and timeout options.
(
address: _Address, options: PoolOptions
)
| 298 | |
| 299 | |
| 300 | async def _configured_protocol_interface( |
| 301 | address: _Address, options: PoolOptions |
| 302 | ) -> AsyncNetworkingInterface: |
| 303 | """Given (host, port) and PoolOptions, return a configured AsyncNetworkingInterface. |
| 304 | |
| 305 | Can raise socket.error, ConnectionFailure, or _CertificateError. |
| 306 | |
| 307 | Sets protocol's SSL and timeout options. |
| 308 | """ |
| 309 | sock = await _async_create_connection(address, options) |
| 310 | ssl_context = options._ssl_context |
| 311 | timeout = options.socket_timeout |
| 312 | |
| 313 | if ssl_context is None: |
| 314 | return AsyncNetworkingInterface( |
| 315 | await asyncio.get_running_loop().create_connection( |
| 316 | lambda: PyMongoProtocol(timeout=timeout), sock=sock |
| 317 | ) |
| 318 | ) |
| 319 | |
| 320 | host = address[0] |
| 321 | try: |
| 322 | # We have to pass hostname / ip address to wrap_socket |
| 323 | # to use SSLContext.check_hostname. |
| 324 | transport, protocol = await asyncio.get_running_loop().create_connection( # type: ignore[call-overload] |
| 325 | lambda: PyMongoProtocol(timeout=timeout), |
| 326 | sock=sock, |
| 327 | server_hostname=host, |
| 328 | ssl=ssl_context, |
| 329 | ) |
| 330 | except _CertificateError: |
| 331 | # Raise _CertificateError directly like we do after match_hostname |
| 332 | # below. |
| 333 | raise |
| 334 | except (OSError, *SSLErrors) as exc: |
| 335 | # We raise AutoReconnect for transient and permanent SSL handshake |
| 336 | # failures alike. Permanent handshake failures, like protocol |
| 337 | # mismatch, will be turned into ServerSelectionTimeoutErrors later. |
| 338 | details = _get_timeout_details(options) |
| 339 | _raise_connection_failure(address, exc, "SSL handshake failed: ", timeout_details=details) |
| 340 | if ( |
| 341 | ssl_context.verify_mode |
| 342 | and not ssl_context.check_hostname |
| 343 | and not options.tls_allow_invalid_hostnames |
| 344 | ): |
| 345 | try: |
| 346 | ssl.match_hostname(transport.get_extra_info("peercert"), hostname=host) # type:ignore[attr-defined,unused-ignore] |
| 347 | except _CertificateError: |
| 348 | transport.abort() |
| 349 | raise |
| 350 | |
| 351 | return AsyncNetworkingInterface((transport, protocol)) |
| 352 | |
| 353 | |
| 354 | def _create_connection(address: _Address, options: PoolOptions) -> socket.socket: |
no test coverage detected