bpo-32069: Drop legacy SSL transport (#4451) · python/cpython@51d546a (original) (raw)

`@@ -74,28 +74,12 @@ def _make_socket_transport(self, sock, protocol, waiter=None, *,

`

74

74

`def _make_ssl_transport(self, rawsock, protocol, sslcontext, waiter=None,

`

75

75

`*, server_side=False, server_hostname=None,

`

76

76

`extra=None, server=None):

`

77

``

`-

if not sslproto._is_sslproto_available():

`

78

``

`-

return self._make_legacy_ssl_transport(

`

79

``

`-

rawsock, protocol, sslcontext, waiter,

`

80

``

`-

server_side=server_side, server_hostname=server_hostname,

`

81

``

`-

extra=extra, server=server)

`

82

``

-

83

77

`ssl_protocol = sslproto.SSLProtocol(self, protocol, sslcontext, waiter,

`

84

78

`server_side, server_hostname)

`

85

79

`_SelectorSocketTransport(self, rawsock, ssl_protocol,

`

86

80

`extra=extra, server=server)

`

87

81

`return ssl_protocol._app_transport

`

88

82

``

89

``

`-

def _make_legacy_ssl_transport(self, rawsock, protocol, sslcontext,

`

90

``

`-

waiter, *,

`

91

``

`-

server_side=False, server_hostname=None,

`

92

``

`-

extra=None, server=None):

`

93

``

`-

Use the legacy API: SSL_write, SSL_read, etc. The legacy API is used

`

94

``

`-

on Python 3.4 and older, when ssl.MemoryBIO is not available.

`

95

``

`-

return _SelectorSslTransport(

`

96

``

`-

self, rawsock, protocol, sslcontext, waiter,

`

97

``

`-

server_side, server_hostname, extra, server)

`

98

``

-

99

83

`def _make_datagram_transport(self, sock, protocol,

`

100

84

`address=None, waiter=None, extra=None):

`

101

85

`return _SelectorDatagramTransport(self, sock, protocol,

`

`@@ -848,238 +832,6 @@ def can_write_eof(self):

`

848

832

`return True

`

849

833

``

850

834

``

851

``

`-

class _SelectorSslTransport(_SelectorTransport):

`

852

``

-

853

``

`-

_buffer_factory = bytearray

`

854

``

-

855

``

`-

def init(self, loop, rawsock, protocol, sslcontext, waiter=None,

`

856

``

`-

server_side=False, server_hostname=None,

`

857

``

`-

extra=None, server=None):

`

858

``

`-

if ssl is None:

`

859

``

`-

raise RuntimeError('stdlib ssl module not available')

`

860

``

-

861

``

`-

if not sslcontext:

`

862

``

`-

sslcontext = sslproto._create_transport_context(server_side, server_hostname)

`

863

``

-

864

``

`-

wrap_kwargs = {

`

865

``

`-

'server_side': server_side,

`

866

``

`-

'do_handshake_on_connect': False,

`

867

``

`-

}

`

868

``

`-

if server_hostname and not server_side:

`

869

``

`-

wrap_kwargs['server_hostname'] = server_hostname

`

870

``

`-

sslsock = sslcontext.wrap_socket(rawsock, **wrap_kwargs)

`

871

``

-

872

``

`-

super().init(loop, sslsock, protocol, extra, server)

`

873

``

`-

the protocol connection is only made after the SSL handshake

`

874

``

`-

self._protocol_connected = False

`

875

``

-

876

``

`-

self._server_hostname = server_hostname

`

877

``

`-

self._waiter = waiter

`

878

``

`-

self._sslcontext = sslcontext

`

879

``

`-

self._paused = False

`

880

``

-

881

``

`-

SSL-specific extra info. (peercert is set later)

`

882

``

`-

self._extra.update(sslcontext=sslcontext)

`

883

``

-

884

``

`-

if self._loop.get_debug():

`

885

``

`-

logger.debug("%r starts SSL handshake", self)

`

886

``

`-

start_time = self._loop.time()

`

887

``

`-

else:

`

888

``

`-

start_time = None

`

889

``

`-

self._on_handshake(start_time)

`

890

``

-

891

``

`-

def _wakeup_waiter(self, exc=None):

`

892

``

`-

if self._waiter is None:

`

893

``

`-

return

`

894

``

`-

if not self._waiter.cancelled():

`

895

``

`-

if exc is not None:

`

896

``

`-

self._waiter.set_exception(exc)

`

897

``

`-

else:

`

898

``

`-

self._waiter.set_result(None)

`

899

``

`-

self._waiter = None

`

900

``

-

901

``

`-

def _on_handshake(self, start_time):

`

902

``

`-

try:

`

903

``

`-

self._sock.do_handshake()

`

904

``

`-

except ssl.SSLWantReadError:

`

905

``

`-

self._loop._add_reader(self._sock_fd,

`

906

``

`-

self._on_handshake, start_time)

`

907

``

`-

return

`

908

``

`-

except ssl.SSLWantWriteError:

`

909

``

`-

self._loop._add_writer(self._sock_fd,

`

910

``

`-

self._on_handshake, start_time)

`

911

``

`-

return

`

912

``

`-

except BaseException as exc:

`

913

``

`-

if self._loop.get_debug():

`

914

``

`-

logger.warning("%r: SSL handshake failed",

`

915

``

`-

self, exc_info=True)

`

916

``

`-

self._loop._remove_reader(self._sock_fd)

`

917

``

`-

self._loop._remove_writer(self._sock_fd)

`

918

``

`-

self._sock.close()

`

919

``

`-

self._wakeup_waiter(exc)

`

920

``

`-

if isinstance(exc, Exception):

`

921

``

`-

return

`

922

``

`-

else:

`

923

``

`-

raise

`

924

``

-

925

``

`-

self._loop._remove_reader(self._sock_fd)

`

926

``

`-

self._loop._remove_writer(self._sock_fd)

`

927

``

-

928

``

`-

peercert = self._sock.getpeercert()

`

929

``

`-

if not hasattr(self._sslcontext, 'check_hostname'):

`

930

``

`-

Verify hostname if requested, Python 3.4+ uses check_hostname

`

931

``

`-

and checks the hostname in do_handshake()

`

932

``

`-

if (self._server_hostname and

`

933

``

`-

self._sslcontext.verify_mode != ssl.CERT_NONE):

`

934

``

`-

try:

`

935

``

`-

ssl.match_hostname(peercert, self._server_hostname)

`

936

``

`-

except Exception as exc:

`

937

``

`-

if self._loop.get_debug():

`

938

``

`-

logger.warning("%r: SSL handshake failed "

`

939

``

`-

"on matching the hostname",

`

940

``

`-

self, exc_info=True)

`

941

``

`-

self._sock.close()

`

942

``

`-

self._wakeup_waiter(exc)

`

943

``

`-

return

`

944

``

-

945

``

`-

Add extra info that becomes available after handshake.

`

946

``

`-

self._extra.update(peercert=peercert,

`

947

``

`-

cipher=self._sock.cipher(),

`

948

``

`-

compression=self._sock.compression(),

`

949

``

`-

ssl_object=self._sock,

`

950

``

`-

)

`

951

``

-

952

``

`-

self._read_wants_write = False

`

953

``

`-

self._write_wants_read = False

`

954

``

`-

self._loop._add_reader(self._sock_fd, self._read_ready)

`

955

``

`-

self._protocol_connected = True

`

956

``

`-

self._loop.call_soon(self._protocol.connection_made, self)

`

957

``

`-

only wake up the waiter when connection_made() has been called

`

958

``

`-

self._loop.call_soon(self._wakeup_waiter)

`

959

``

-

960

``

`-

if self._loop.get_debug():

`

961

``

`-

dt = self._loop.time() - start_time

`

962

``

`-

logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)

`

963

``

-

964

``

`-

def pause_reading(self):

`

965

``

`-

XXX This is a bit icky, given the comment at the top of

`

966

``

`-

_read_ready(). Is it possible to evoke a deadlock? I don't

`

967

``

`-

know, although it doesn't look like it; write() will still

`

968

``

`-

accept more data for the buffer and eventually the app will

`

969

``

`-

call resume_reading() again, and things will flow again.

`

970

``

-

971

``

`-

if self._closing:

`

972

``

`-

raise RuntimeError('Cannot pause_reading() when closing')

`

973

``

`-

if self._paused:

`

974

``

`-

raise RuntimeError('Already paused')

`

975

``

`-

self._paused = True

`

976

``

`-

self._loop._remove_reader(self._sock_fd)

`

977

``

`-

if self._loop.get_debug():

`

978

``

`-

logger.debug("%r pauses reading", self)

`

979

``

-

980

``

`-

def resume_reading(self):

`

981

``

`-

if not self._paused:

`

982

``

`-

raise RuntimeError('Not paused')

`

983

``

`-

self._paused = False

`

984

``

`-

if self._closing:

`

985

``

`-

return

`

986

``

`-

self._loop._add_reader(self._sock_fd, self._read_ready)

`

987

``

`-

if self._loop.get_debug():

`

988

``

`-

logger.debug("%r resumes reading", self)

`

989

``

-

990

``

`-

def _read_ready(self):

`

991

``

`-

if self._conn_lost:

`

992

``

`-

return

`

993

``

`-

if self._write_wants_read:

`

994

``

`-

self._write_wants_read = False

`

995

``

`-

self._write_ready()

`

996

``

-

997

``

`-

if self._buffer:

`

998

``

`-

self._loop._add_writer(self._sock_fd, self._write_ready)

`

999

``

-

1000

``

`-

try:

`

1001

``

`-

data = self._sock.recv(self.max_size)

`

1002

``

`-

except (BlockingIOError, InterruptedError, ssl.SSLWantReadError):

`

1003

``

`-

pass

`

1004

``

`-

except ssl.SSLWantWriteError:

`

1005

``

`-

self._read_wants_write = True

`

1006

``

`-

self._loop._remove_reader(self._sock_fd)

`

1007

``

`-

self._loop._add_writer(self._sock_fd, self._write_ready)

`

1008

``

`-

except Exception as exc:

`

1009

``

`-

self._fatal_error(exc, 'Fatal read error on SSL transport')

`

1010

``

`-

else:

`

1011

``

`-

if data:

`

1012

``

`-

self._protocol.data_received(data)

`

1013

``

`-

else:

`

1014

``

`-

try:

`

1015

``

`-

if self._loop.get_debug():

`

1016

``

`-

logger.debug("%r received EOF", self)

`

1017

``

`-

keep_open = self._protocol.eof_received()

`

1018

``

`-

if keep_open:

`

1019

``

`-

logger.warning('returning true from eof_received() '

`

1020

``

`-

'has no effect when using ssl')

`

1021

``

`-

finally:

`

1022

``

`-

self.close()

`

1023

``

-

1024

``

`-

def _write_ready(self):

`

1025

``

`-

if self._conn_lost:

`

1026

``

`-

return

`

1027

``

`-

if self._read_wants_write:

`

1028

``

`-

self._read_wants_write = False

`

1029

``

`-

self._read_ready()

`

1030

``

-

1031

``

`-

if not (self._paused or self._closing):

`

1032

``

`-

self._loop._add_reader(self._sock_fd, self._read_ready)

`

1033

``

-

1034

``

`-

if self._buffer:

`

1035

``

`-

try:

`

1036

``

`-

n = self._sock.send(self._buffer)

`

1037

``

`-

except (BlockingIOError, InterruptedError, ssl.SSLWantWriteError):

`

1038

``

`-

n = 0

`

1039

``

`-

except ssl.SSLWantReadError:

`

1040

``

`-

n = 0

`

1041

``

`-

self._loop._remove_writer(self._sock_fd)

`

1042

``

`-

self._write_wants_read = True

`

1043

``

`-

except Exception as exc:

`

1044

``

`-

self._loop._remove_writer(self._sock_fd)

`

1045

``

`-

self._buffer.clear()

`

1046

``

`-

self._fatal_error(exc, 'Fatal write error on SSL transport')

`

1047

``

`-

return

`

1048

``

-

1049

``

`-

if n:

`

1050

``

`-

del self._buffer[:n]

`

1051

``

-

1052

``

`-

self._maybe_resume_protocol() # May append to buffer.

`

1053

``

-

1054

``

`-

if not self._buffer:

`

1055

``

`-

self._loop._remove_writer(self._sock_fd)

`

1056

``

`-

if self._closing:

`

1057

``

`-

self._call_connection_lost(None)

`

1058

``

-

1059

``

`-

def write(self, data):

`

1060

``

`-

if not isinstance(data, (bytes, bytearray, memoryview)):

`

1061

``

`-

raise TypeError('data argument must be a bytes-like object, '

`

1062

``

`-

'not %r' % type(data).name)

`

1063

``

`-

if not data:

`

1064

``

`-

return

`

1065

``

-

1066

``

`-

if self._conn_lost:

`

1067

``

`-

if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:

`

1068

``

`-

logger.warning('socket.send() raised exception.')

`

1069

``

`-

self._conn_lost += 1

`

1070

``

`-

return

`

1071

``

-

1072

``

`-

if not self._buffer:

`

1073

``

`-

self._loop._add_writer(self._sock_fd, self._write_ready)

`

1074

``

-

1075

``

`-

Add it to the buffer.

`

1076

``

`-

self._buffer.extend(data)

`

1077

``

`-

self._maybe_pause_protocol()

`

1078

``

-

1079

``

`-

def can_write_eof(self):

`

1080

``

`-

return False

`

1081

``

-

1082

``

-

1083

835

`class _SelectorDatagramTransport(_SelectorTransport):

`

1084

836

``

1085

837

`_buffer_factory = collections.deque

`