Skip to content

Commit 92016be

Browse files
committed
PEP 748: shutdown(show: 0|1|2) instead of close(force: bool)
1 parent 506c877 commit 92016be

1 file changed

Lines changed: 42 additions & 10 deletions

File tree

peps/pep-0748.rst

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ need to implement the following:
422422

423423
* ``recv`` and ``send``
424424
* ``accept`` (server-side)
425-
* ``close``
425+
* ``shutdown`` and ``close``
426426
* ``getsockname``
427427
* ``getpeername``
428428

@@ -438,6 +438,12 @@ The following code describes these functions in more detail:
438438

439439
.. code-block:: python
440440
441+
class TLSShutdownMode(enum.IntEnum):
442+
SHUT_RD = 0
443+
SHUT_WR = 1
444+
SHUT_RDWR = 2
445+
446+
441447
class TLSSocket(Protocol):
442448
"""This class implements a socket.socket-like object that creates an OS
443449
socket, wraps it in an SSL context, and provides read and write methods
@@ -464,15 +470,41 @@ The following code describes these functions in more detail:
464470
...
465471
466472
@abstractmethod
467-
def close(self, force: bool = False) -> None:
468-
"""Shuts down the connection and mark the socket closed.
469-
If force is True, this method should send the close_notify alert and shut down
470-
the socket without waiting for the other side.
471-
If force is False, this method should send the close_notify alert and raise
472-
the WantReadError exception until a corresponding close_notify alert has been
473-
received from the other side.
474-
In either case, this method should return WantWriteError if sending the
475-
close_notify alert currently fails."""
473+
def shutdown(self, how: TLSShutdownMode) -> None:
474+
"""
475+
Shutdown TLS and the underlying socket.
476+
477+
* ``SHUT_RD`` (``0``) unilateraly close the receiving-side: discard
478+
present and future unread messages.
479+
* ``SHUT_WR`` (``1``) gracefully close the sending-side: send a
480+
closing alert and prevent sending more messages.
481+
* ``SHUT_RDWR`` (``2``): both ``SHUT_WR`` and ``SHUT_RD``.
482+
483+
.. danger::
484+
485+
Both ``shutdown(SHUT_RD)`` and ``shutdown(SHUT_RDWR)`` pose a
486+
risk of data loss: they are unsafe unless the connection is
487+
otherwise known to be over or when truncation is not an issue.
488+
489+
In TLS 1.2, the same risk applies also to ``shutdown(SHUT_WR)``.
490+
"""
491+
...
492+
493+
@abstractmethod
494+
def close(self) -> None:
495+
"""
496+
Close the underlying socket, but only when it is safe to do so.
497+
498+
When the sending-side of the connection is still open, it gracefully
499+
closes the TLS sending-side before closing the socket, raising
500+
``WantWriteError`` when it fails.
501+
502+
When the receiving-side of the connection is still open, it always
503+
raises ``WantReadError`` as there's a risk of data loss / truncation
504+
attack. The user must first either: (safe) ``recv`` until the peer
505+
closes its sending-side of the connection, or (unsafe) take the risk
506+
and unilateraly ``shutdown`` the receiving-side of the connection.
507+
"""
476508
...
477509
478510
@abstractmethod

0 commit comments

Comments
 (0)