mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Issue #23197, asyncio: On SSL handshake failure, check if the waiter is
cancelled before setting its exception. * Add unit tests for this case. * Cleanup also sslproto.py
This commit is contained in:
		
							parent
							
								
									f651a60407
								
							
						
					
					
						commit
						177e9f0855
					
				
					 4 changed files with 65 additions and 7 deletions
				
			
		|  | @ -750,7 +750,7 @@ def _on_handshake(self, start_time): | |||
|             self._loop.remove_reader(self._sock_fd) | ||||
|             self._loop.remove_writer(self._sock_fd) | ||||
|             self._sock.close() | ||||
|             if self._waiter is not None: | ||||
|             if self._waiter is not None and not self._waiter.cancelled(): | ||||
|                 self._waiter.set_exception(exc) | ||||
|             if isinstance(exc, Exception): | ||||
|                 return | ||||
|  |  | |||
|  | @ -530,10 +530,11 @@ def _on_handshake_complete(self, handshake_exc): | |||
|         self._in_handshake = False | ||||
| 
 | ||||
|         sslobj = self._sslpipe.ssl_object | ||||
|         peercert = None if handshake_exc else sslobj.getpeercert() | ||||
|         try: | ||||
|             if handshake_exc is not None: | ||||
|                 raise handshake_exc | ||||
| 
 | ||||
|             peercert = sslobj.getpeercert() | ||||
|             if not hasattr(self._sslcontext, 'check_hostname'): | ||||
|                 # Verify hostname if requested, Python 3.4+ uses check_hostname | ||||
|                 # and checks the hostname in do_handshake() | ||||
|  | @ -551,7 +552,7 @@ def _on_handshake_complete(self, handshake_exc): | |||
|                                    self, exc_info=True) | ||||
|             self._transport.close() | ||||
|             if isinstance(exc, Exception): | ||||
|                 if self._waiter is not None: | ||||
|                 if self._waiter is not None and not self._waiter.cancelled(): | ||||
|                     self._waiter.set_exception(exc) | ||||
|                 return | ||||
|             else: | ||||
|  |  | |||
|  | @ -1148,16 +1148,28 @@ def test_on_handshake_exc(self): | |||
|         self.assertTrue(self.sslsock.close.called) | ||||
| 
 | ||||
|     def test_on_handshake_base_exc(self): | ||||
|         waiter = asyncio.Future(loop=self.loop) | ||||
|         transport = _SelectorSslTransport( | ||||
|             self.loop, self.sock, self.protocol, self.sslcontext) | ||||
|         transport._waiter = asyncio.Future(loop=self.loop) | ||||
|             self.loop, self.sock, self.protocol, self.sslcontext, waiter) | ||||
|         exc = BaseException() | ||||
|         self.sslsock.do_handshake.side_effect = exc | ||||
|         with test_utils.disable_logger(): | ||||
|             self.assertRaises(BaseException, transport._on_handshake, 0) | ||||
|         self.assertTrue(self.sslsock.close.called) | ||||
|         self.assertTrue(transport._waiter.done()) | ||||
|         self.assertIs(exc, transport._waiter.exception()) | ||||
|         self.assertTrue(waiter.done()) | ||||
|         self.assertIs(exc, waiter.exception()) | ||||
| 
 | ||||
|     def test_cancel_handshake(self): | ||||
|         # Python issue #23197: cancelling an handshake must not raise an | ||||
|         # exception or log an error, even if the handshake failed | ||||
|         waiter = asyncio.Future(loop=self.loop) | ||||
|         transport = _SelectorSslTransport( | ||||
|             self.loop, self.sock, self.protocol, self.sslcontext, waiter) | ||||
|         waiter.cancel() | ||||
|         exc = ValueError() | ||||
|         self.sslsock.do_handshake.side_effect = exc | ||||
|         with test_utils.disable_logger(): | ||||
|             transport._on_handshake(0) | ||||
| 
 | ||||
|     def test_pause_resume_reading(self): | ||||
|         tr = self._make_one() | ||||
|  |  | |||
							
								
								
									
										45
									
								
								Lib/test/test_asyncio/test_sslproto.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Lib/test/test_asyncio/test_sslproto.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| """Tests for asyncio/sslproto.py.""" | ||||
| 
 | ||||
| import unittest | ||||
| from unittest import mock | ||||
| 
 | ||||
| import asyncio | ||||
| from asyncio import sslproto | ||||
| from asyncio import test_utils | ||||
| 
 | ||||
| 
 | ||||
| class SslProtoHandshakeTests(test_utils.TestCase): | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.loop = asyncio.new_event_loop() | ||||
|         self.set_event_loop(self.loop) | ||||
| 
 | ||||
|     def test_cancel_handshake(self): | ||||
|         # Python issue #23197: cancelling an handshake must not raise an | ||||
|         # exception or log an error, even if the handshake failed | ||||
|         sslcontext = test_utils.dummy_ssl_context() | ||||
|         app_proto = asyncio.Protocol() | ||||
|         waiter = asyncio.Future(loop=self.loop) | ||||
|         ssl_proto = sslproto.SSLProtocol(self.loop, app_proto, sslcontext, | ||||
|                                          waiter) | ||||
|         handshake_fut = asyncio.Future(loop=self.loop) | ||||
| 
 | ||||
|         def do_handshake(callback): | ||||
|             exc = Exception() | ||||
|             callback(exc) | ||||
|             handshake_fut.set_result(None) | ||||
|             return [] | ||||
| 
 | ||||
|         waiter.cancel() | ||||
|         transport = mock.Mock() | ||||
|         sslpipe = mock.Mock() | ||||
|         sslpipe.do_handshake.side_effect = do_handshake | ||||
|         with mock.patch('asyncio.sslproto._SSLPipe', return_value=sslpipe): | ||||
|             ssl_proto.connection_made(transport) | ||||
| 
 | ||||
|         with test_utils.disable_logger(): | ||||
|             self.loop.run_until_complete(handshake_fut) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     unittest.main() | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner