FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix: Clarify fd ownership and align tests by mistotebe · Pull Request #623 · python-ldap/python-ldap · GitHub

Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (2) .rst  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
23 changes: 17 additions & 6 deletions Doc/reference/ldap.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,25 @@ This module defines the following functions:
connect to an LDAP server. The *fileno* must either be a socket file
descriptor as :class:`int` or a file-like object with a *fileno()* method
that returns a socket file descriptor. The socket file descriptor must
already be connected. :class:`~ldap.ldapobject.LDAPObject` does not take
ownership of the file descriptor. It must be kept open during operations
and explicitly closed after the :class:`~ldap.ldapobject.LDAPObject` is
unbound. The internal connection type is determined from the URI, ``TCP``
for ``ldap://`` / ``ldaps://``, ``IPC`` (``AF_UNIX``) for ``ldapi://``.
The parameter is not available on macOS when python-ldap is compiled with system
already be connected. :class:`~ldap.ldapobject.LDAPObject` takes ownership of
the file descriptor on creation which must be left alone and will be
automatically closed after the :class:`~ldap.ldapobject.LDAPObject` is
unbound. The internal connection type is determined from the URI, ``TCP`` for
``ldap://`` / ``ldaps://``, ``IPC`` (``AF_UNIX``) for ``ldapi://``. The
parameter is not available on macOS when python-ldap is compiled with system
libldap, see :py:const:`INIT_FD_AVAIL`.

.. warning::

The documentation used to suggest (wrongly) that the object would not take
ownership of the file descriptor in *fileno*. It does. If using *fileno*,
detach the socket it came from as soon as you use it to obtain an instance
of :class:`~ldap.ldapobject.LDAPObject`::

sock = socket.create_connection((host, port))
conn = ldap.initialize(uri, fileno=sock.fileno())
sock.detach()

Note that internally the OpenLDAP function
`ldap_initialize(3) <https://www.openldap.org/software/man.cgi?query=ldap_init&sektion=3>`_
is called which just initializes the LDAP connection struct in the C API
Expand Down
4 changes: 3 additions & 1 deletion Lib/ldap/functions.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ def initialize(
Whether to enable :ref:`bytes_mode` for backwards compatibility under Py2.
fileno
If not None the socket file descriptor is used to connect to an
LDAP server.
LDAP server. The connection takes ownership of the descriptor and
closes it when unbound, so nothing else may close it. Detach the
socket object it came from.

Additional keyword arguments (such as ``bytes_strictness``) are
passed to ``LDAPObject``.
Expand Down
37 changes: 20 additions & 17 deletions Tests/t_cext.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,13 @@ def _open_conn_fd(self, bind=True):
)
try:
l = _ldap.initialize_fd(sock.fileno(), self.server.ldap_uri)
if bind:
self._bind_conn(l)
yield sock, l
finally:
try:
sock.close()
except OSError:
# already closed
pass
except Exception:
sock.close()
raise
fd = sock.detach()
if bind:
self._bind_conn(l)
yield fd, l

def _bind_conn(self, l):
# Perform a simple bind
Expand Down Expand Up @@ -244,27 +242,32 @@ def test_simple_bind(self):
l = self._open_conn()

def test_simple_bind_fileno(self):
with self._open_conn_fd() as (sock, l):
with self._open_conn_fd() as (fd, l):
self.assertEqual(l.whoami_s(), "dn:" + self.server.root_dn)

@requires_init_fd()
def test_simple_bind_fileno_invalid(self):
with open(os.devnull) as f:
l = _ldap.initialize_fd(f.fileno(), self.server.ldap_uri)
with self.assertRaises(_ldap.SERVER_DOWN):
self._bind_conn(l)
fd = os.open(os.devnull, os.O_RDWR)
l = _ldap.initialize_fd(fd, self.server.ldap_uri)
with self.assertRaises(_ldap.SERVER_DOWN):
self._bind_conn(l)
l.unbind_ext()

@requires_init_fd()
def test_simple_bind_fileno_closed(self):
with self._open_conn_fd() as (sock, l):
with self._open_conn_fd() as (fd, l):
self.assertEqual(l.whoami_s(), "dn:" + self.server.root_dn)
sock.close()

sock = socket.socket(fileno=fd)
sock.shutdown(socket.SHUT_RDWR)
sock.detach()

with self.assertRaises(_ldap.SERVER_DOWN):
l.whoami_s()

@requires_init_fd()
def test_simple_bind_fileno_rebind(self):
with self._open_conn_fd() as (sock, l):
with self._open_conn_fd() as (fd, l):
self.assertEqual(l.whoami_s(), "dn:" + self.server.root_dn)
l.unbind_ext()
with self.assertRaises(_ldap.LDAPError):
Expand Down

Back | FazBrowse Home | New Git URL