Skip to content

Commit 850ff33

Browse files
committed
Fix encryption
1 parent ca1d208 commit 850ff33

File tree

6 files changed

+150
-305
lines changed

6 files changed

+150
-305
lines changed

pymongo/asynchronous/encryption.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
cast,
3939
)
4040

41-
from pymongo.asynchronous.pool import _async_configured_socket
41+
from pymongo.pool_shared import _async_configured_socket
4242

4343
try:
4444
from pymongocrypt.asynchronous.auto_encrypter import AsyncAutoEncrypter # type:ignore[import]

pymongo/asynchronous/pool.py

Lines changed: 2 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,10 @@
1414

1515
from __future__ import annotations
1616

17-
import asyncio
1817
import collections
1918
import contextlib
20-
import functools
2119
import logging
2220
import os
23-
import socket
24-
import ssl
2521
import sys
2622
import time
2723
import weakref
@@ -40,7 +36,7 @@
4036
from bson import DEFAULT_CODEC_OPTIONS
4137
from pymongo import _csot, helpers_shared
4238
from pymongo.asynchronous.client_session import _validate_session_write_concern
43-
from pymongo.asynchronous.helpers import _getaddrinfo, _handle_reauth
39+
from pymongo.asynchronous.helpers import _handle_reauth
4440
from pymongo.asynchronous.network import command
4541
from pymongo.common import (
4642
MAX_BSON_SIZE,
@@ -52,15 +48,13 @@
5248
from pymongo.errors import ( # type:ignore[attr-defined]
5349
AutoReconnect,
5450
ConfigurationError,
55-
ConnectionFailure,
5651
DocumentTooLarge,
5752
ExecutionTimeout,
5853
InvalidOperation,
5954
NotPrimaryError,
6055
OperationFailure,
6156
PyMongoError,
6257
WaitQueueTimeoutError,
63-
_CertificateError,
6458
)
6559
from pymongo.hello import Hello, HelloCompat
6660
from pymongo.lock import (
@@ -85,14 +79,13 @@
8579
_configured_protocol,
8680
_get_timeout_details,
8781
_raise_connection_failure,
88-
_set_keepalive_times,
8982
format_timeout_details,
9083
)
9184
from pymongo.read_preferences import ReadPreference
9285
from pymongo.server_api import _add_to_command
9386
from pymongo.server_type import SERVER_TYPE
9487
from pymongo.socket_checker import SocketChecker
95-
from pymongo.ssl_support import HAS_SNI, SSLError
88+
from pymongo.ssl_support import SSLError
9689

9790
if TYPE_CHECKING:
9891
from bson import CodecOptions
@@ -106,7 +99,6 @@
10699
ZstdContext,
107100
)
108101
from pymongo.message import _OpMsg, _OpReply
109-
from pymongo.pyopenssl_context import _sslConn
110102
from pymongo.read_concern import ReadConcern
111103
from pymongo.read_preferences import _ServerMode
112104
from pymongo.typings import ClusterTime, _Address, _CollationIn
@@ -670,145 +662,6 @@ def __repr__(self) -> str:
670662
)
671663

672664

673-
async def _async_create_connection(address: _Address, options: PoolOptions) -> socket.socket:
674-
"""Given (host, port) and PoolOptions, connect and return a socket object.
675-
676-
Can raise socket.error.
677-
678-
This is a modified version of create_connection from CPython >= 2.7.
679-
"""
680-
host, port = address
681-
682-
# Check if dealing with a unix domain socket
683-
if host.endswith(".sock"):
684-
if not hasattr(socket, "AF_UNIX"):
685-
raise ConnectionFailure("UNIX-sockets are not supported on this system")
686-
sock = socket.socket(socket.AF_UNIX)
687-
# SOCK_CLOEXEC not supported for Unix sockets.
688-
_set_non_inheritable_non_atomic(sock.fileno())
689-
try:
690-
sock.connect(host)
691-
return sock
692-
except OSError:
693-
sock.close()
694-
raise
695-
696-
# Don't try IPv6 if we don't support it. Also skip it if host
697-
# is 'localhost' (::1 is fine). Avoids slow connect issues
698-
# like PYTHON-356.
699-
family = socket.AF_INET
700-
if socket.has_ipv6 and host != "localhost":
701-
family = socket.AF_UNSPEC
702-
703-
err = None
704-
for res in await _getaddrinfo(host, port, family=family, type=socket.SOCK_STREAM): # type: ignore[attr-defined]
705-
af, socktype, proto, dummy, sa = res
706-
# SOCK_CLOEXEC was new in CPython 3.2, and only available on a limited
707-
# number of platforms (newer Linux and *BSD). Starting with CPython 3.4
708-
# all file descriptors are created non-inheritable. See PEP 446.
709-
try:
710-
sock = socket.socket(af, socktype | getattr(socket, "SOCK_CLOEXEC", 0), proto)
711-
except OSError:
712-
# Can SOCK_CLOEXEC be defined even if the kernel doesn't support
713-
# it?
714-
sock = socket.socket(af, socktype, proto)
715-
# Fallback when SOCK_CLOEXEC isn't available.
716-
_set_non_inheritable_non_atomic(sock.fileno())
717-
try:
718-
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
719-
# CSOT: apply timeout to socket connect.
720-
timeout = _csot.remaining()
721-
if timeout is None:
722-
timeout = options.connect_timeout
723-
elif timeout <= 0:
724-
raise socket.timeout("timed out")
725-
sock.settimeout(timeout)
726-
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, True)
727-
_set_keepalive_times(sock)
728-
sock.connect(sa)
729-
return sock
730-
except OSError as e:
731-
err = e
732-
sock.close()
733-
734-
if err is not None:
735-
raise err
736-
else:
737-
# This likely means we tried to connect to an IPv6 only
738-
# host with an OS/kernel or Python interpreter that doesn't
739-
# support IPv6. The test case is Jython2.5.1 which doesn't
740-
# support IPv6 at all.
741-
raise OSError("getaddrinfo failed")
742-
743-
744-
async def _async_configured_socket(
745-
address: _Address, options: PoolOptions
746-
) -> Union[socket.socket, _sslConn]:
747-
"""Given (host, port) and PoolOptions, return a configured socket.
748-
749-
Can raise socket.error, ConnectionFailure, or _CertificateError.
750-
751-
Sets socket's SSL and timeout options.
752-
"""
753-
sock = await _async_create_connection(address, options)
754-
ssl_context = options._ssl_context
755-
756-
if ssl_context is None:
757-
sock.settimeout(options.socket_timeout)
758-
return sock
759-
760-
host = address[0]
761-
try:
762-
# We have to pass hostname / ip address to wrap_socket
763-
# to use SSLContext.check_hostname.
764-
if HAS_SNI:
765-
if _IS_SYNC:
766-
ssl_sock = ssl_context.wrap_socket(sock, server_hostname=host)
767-
else:
768-
if hasattr(ssl_context, "a_wrap_socket"):
769-
ssl_sock = await ssl_context.a_wrap_socket(sock, server_hostname=host) # type: ignore[assignment, misc]
770-
else:
771-
loop = asyncio.get_running_loop()
772-
ssl_sock = await loop.run_in_executor(
773-
None,
774-
functools.partial(ssl_context.wrap_socket, sock, server_hostname=host), # type: ignore[assignment, misc]
775-
)
776-
else:
777-
if _IS_SYNC:
778-
ssl_sock = ssl_context.wrap_socket(sock)
779-
else:
780-
if hasattr(ssl_context, "a_wrap_socket"):
781-
ssl_sock = await ssl_context.a_wrap_socket(sock) # type: ignore[assignment, misc]
782-
else:
783-
loop = asyncio.get_running_loop()
784-
ssl_sock = await loop.run_in_executor(None, ssl_context.wrap_socket, sock) # type: ignore[assignment, misc]
785-
except _CertificateError:
786-
sock.close()
787-
# Raise _CertificateError directly like we do after match_hostname
788-
# below.
789-
raise
790-
except (OSError, SSLError) as exc:
791-
sock.close()
792-
# We raise AutoReconnect for transient and permanent SSL handshake
793-
# failures alike. Permanent handshake failures, like protocol
794-
# mismatch, will be turned into ServerSelectionTimeoutErrors later.
795-
details = _get_timeout_details(options)
796-
_raise_connection_failure(address, exc, "SSL handshake failed: ", timeout_details=details)
797-
if (
798-
ssl_context.verify_mode
799-
and not ssl_context.check_hostname
800-
and not options.tls_allow_invalid_hostnames
801-
):
802-
try:
803-
ssl.match_hostname(ssl_sock.getpeercert(), hostname=host) # type:ignore[attr-defined]
804-
except _CertificateError:
805-
ssl_sock.close()
806-
raise
807-
808-
ssl_sock.settimeout(options.socket_timeout)
809-
return ssl_sock
810-
811-
812665
class _PoolClosedError(PyMongoError):
813666
"""Internal error raised when a thread tries to get a connection from a
814667
closed pool.

0 commit comments

Comments
 (0)