@@ -2608,10 +2608,6 @@ async def client(addr):
26082608 self .loop .run_until_complete (client (srv .addr ))
26092609
26102610 def test_remote_shutdown_receives_trailing_data (self ):
2611- if self .implementation == 'asyncio' :
2612- # this is an issue in asyncio
2613- raise unittest .SkipTest ()
2614-
26152611 CHUNK = 1024 * 16
26162612 SIZE = 8
26172613 count = 0
@@ -2676,13 +2672,18 @@ def server(sock):
26762672 data_len += chunk
26772673 except ssl .SSLWantReadError :
26782674 incoming .write (sock .recv (16384 ))
2675+ if not incoming .pending :
2676+ # EOF received
2677+ break
26792678 except ssl .SSLZeroReturnError :
26802679 break
26812680
26822681 self .assertEqual (data_len , CHUNK * count )
26832682
2684- # verify that close_notify is received
2685- sslobj .unwrap ()
2683+ if self .implementation == 'uvloop' :
2684+ # Verify that close_notify is received. asyncio is currently
2685+ # not guaranteed to send close_notify before dropping off
2686+ sslobj .unwrap ()
26862687
26872688 sock .close ()
26882689
@@ -2708,11 +2709,12 @@ async def client(addr):
27082709 await asyncio .wait_for (
27092710 asyncio .ensure_future (writer .drain ()), 0.5 )
27102711 except asyncio .TimeoutError :
2711- # fill write backlog in a hacky way
2712- for _ in range (SIZE ):
2713- writer .transport ._test__append_write_backlog (
2714- b'x' * CHUNK )
2715- count += 1
2712+ # fill write backlog in a hacky way for uvloop
2713+ if self .implementation == 'uvloop' :
2714+ for _ in range (SIZE ):
2715+ writer .transport ._test__append_write_backlog (
2716+ b'x' * CHUNK )
2717+ count += 1
27162718
27172719 data = await reader .read ()
27182720 self .assertEqual (data , b'' )
@@ -2929,7 +2931,7 @@ def server(sock):
29292931 except ssl .SSLWantReadError :
29302932 if outgoing .pending :
29312933 sock .send (outgoing .read ())
2932- # incoming.write(sock.recv(16384))
2934+ incoming .write (sock .recv (16384 ))
29332935 else :
29342936 if outgoing .pending :
29352937 sock .send (outgoing .read ())
@@ -2963,12 +2965,94 @@ async def client(addr):
29632965 tr .pause_reading ()
29642966 tr .close ()
29652967
2966- await eof_recvd
2967- await conn_lost
2968+ await asyncio . wait_for ( eof_recvd , 10 )
2969+ await asyncio . wait_for ( conn_lost , 10 )
29682970
29692971 with self .tcp_server (server ) as srv :
29702972 loop .run_until_complete (client (srv .addr ))
29712973
2974+ def test_bpo_39951_discard_trailing_data (self ):
2975+ sslctx = self ._create_server_ssl_context (self .ONLYCERT , self .ONLYKEY )
2976+ client_sslctx = self ._create_client_ssl_context ()
2977+ future = None
2978+ close_notify = threading .Lock ()
2979+
2980+ def server (sock ):
2981+ incoming = ssl .MemoryBIO ()
2982+ outgoing = ssl .MemoryBIO ()
2983+ sslobj = sslctx .wrap_bio (incoming , outgoing , server_side = True )
2984+
2985+ while True :
2986+ try :
2987+ sslobj .do_handshake ()
2988+ except ssl .SSLWantReadError :
2989+ if outgoing .pending :
2990+ sock .send (outgoing .read ())
2991+ incoming .write (sock .recv (16384 ))
2992+ else :
2993+ if outgoing .pending :
2994+ sock .send (outgoing .read ())
2995+ break
2996+
2997+ while True :
2998+ try :
2999+ data = sslobj .read (4 )
3000+ except ssl .SSLWantReadError :
3001+ incoming .write (sock .recv (16384 ))
3002+ else :
3003+ break
3004+
3005+ self .assertEqual (data , b'ping' )
3006+ sslobj .write (b'pong' )
3007+ sock .send (outgoing .read ())
3008+
3009+ with close_notify :
3010+ sslobj .write (b'trailing' )
3011+ sock .send (outgoing .read ())
3012+ time .sleep (0.5 ) # allow time for the client to receive
3013+
3014+ incoming .write (sock .recv (16384 ))
3015+ sslobj .unwrap ()
3016+ sock .send (outgoing .read ())
3017+ sock .close ()
3018+
3019+ async def client (addr ):
3020+ nonlocal future
3021+ future = self .loop .create_future ()
3022+
3023+ with close_notify :
3024+ reader , writer = await asyncio .open_connection (
3025+ * addr ,
3026+ ssl = client_sslctx ,
3027+ server_hostname = '' )
3028+ writer .write (b'ping' )
3029+ data = await reader .readexactly (4 )
3030+ self .assertEqual (data , b'pong' )
3031+
3032+ writer .close ()
3033+
3034+ try :
3035+ await self .wait_closed (writer )
3036+ except ssl .SSLError as e :
3037+ if self .implementation == 'asyncio' and \
3038+ 'application data after close notify' in str (e ):
3039+ raise unittest .SkipTest ('bpo-39951' )
3040+ raise
3041+ await future
3042+
3043+ def run (meth ):
3044+ def wrapper (sock ):
3045+ try :
3046+ meth (sock )
3047+ except Exception as ex :
3048+ self .loop .call_soon_threadsafe (future .set_exception , ex )
3049+ else :
3050+ self .loop .call_soon_threadsafe (future .set_result , None )
3051+ return wrapper
3052+
3053+ with self .tcp_server (run (server )) as srv :
3054+ self .loop .run_until_complete (client (srv .addr ))
3055+
29723056
29733057class Test_UV_TCPSSL (_TestSSL , tb .UVTestCase ):
29743058 pass
0 commit comments