mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	bpo-35065: Remove StreamReaderProtocol._untrack_reader (#10212)
				
					
				
			The call to `_untrack_reader` is performed too soon, causing the protocol to forget about the reader before `connection_lost` can run and feed the EOF to the reader. See bpo-35065.
This commit is contained in:
		
							parent
							
								
									5d95312fb8
								
							
						
					
					
						commit
						fd512d7645
					
				
					 4 changed files with 26 additions and 11 deletions
				
			
		|  | @ -227,9 +227,6 @@ def _on_reader_gc(self, wr): | ||||||
|             self._reject_connection = True |             self._reject_connection = True | ||||||
|         self._stream_reader_wr = None |         self._stream_reader_wr = None | ||||||
| 
 | 
 | ||||||
|     def _untrack_reader(self): |  | ||||||
|         self._stream_reader_wr = None |  | ||||||
| 
 |  | ||||||
|     @property |     @property | ||||||
|     def _stream_reader(self): |     def _stream_reader(self): | ||||||
|         if self._stream_reader_wr is None: |         if self._stream_reader_wr is None: | ||||||
|  | @ -345,9 +342,6 @@ def can_write_eof(self): | ||||||
|         return self._transport.can_write_eof() |         return self._transport.can_write_eof() | ||||||
| 
 | 
 | ||||||
|     def close(self): |     def close(self): | ||||||
|         # a reader can be garbage collected |  | ||||||
|         # after connection closing |  | ||||||
|         self._protocol._untrack_reader() |  | ||||||
|         self._transport.close() |         self._transport.close() | ||||||
| 
 | 
 | ||||||
|     def is_closing(self): |     def is_closing(self): | ||||||
|  |  | ||||||
|  | @ -36,11 +36,6 @@ def __repr__(self): | ||||||
|             info.append(f'stderr={self.stderr!r}') |             info.append(f'stderr={self.stderr!r}') | ||||||
|         return '<{}>'.format(' '.join(info)) |         return '<{}>'.format(' '.join(info)) | ||||||
| 
 | 
 | ||||||
|     def _untrack_reader(self): |  | ||||||
|         # StreamWriter.close() expects the protocol |  | ||||||
|         # to have this method defined. |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     def connection_made(self, transport): |     def connection_made(self, transport): | ||||||
|         self._transport = transport |         self._transport = transport | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -589,6 +589,7 @@ async def handle_client(self, client_reader, client_writer): | ||||||
|                 client_writer.write(data) |                 client_writer.write(data) | ||||||
|                 await client_writer.drain() |                 await client_writer.drain() | ||||||
|                 client_writer.close() |                 client_writer.close() | ||||||
|  |                 await client_writer.wait_closed() | ||||||
| 
 | 
 | ||||||
|             def start(self): |             def start(self): | ||||||
|                 sock = socket.socket() |                 sock = socket.socket() | ||||||
|  | @ -628,6 +629,7 @@ async def client(addr): | ||||||
|             # read it back |             # read it back | ||||||
|             msgback = await reader.readline() |             msgback = await reader.readline() | ||||||
|             writer.close() |             writer.close() | ||||||
|  |             await writer.wait_closed() | ||||||
|             return msgback |             return msgback | ||||||
| 
 | 
 | ||||||
|         messages = [] |         messages = [] | ||||||
|  | @ -666,6 +668,7 @@ async def handle_client(self, client_reader, client_writer): | ||||||
|                 client_writer.write(data) |                 client_writer.write(data) | ||||||
|                 await client_writer.drain() |                 await client_writer.drain() | ||||||
|                 client_writer.close() |                 client_writer.close() | ||||||
|  |                 await client_writer.wait_closed() | ||||||
| 
 | 
 | ||||||
|             def start(self): |             def start(self): | ||||||
|                 self.server = self.loop.run_until_complete( |                 self.server = self.loop.run_until_complete( | ||||||
|  | @ -697,6 +700,7 @@ async def client(path): | ||||||
|             # read it back |             # read it back | ||||||
|             msgback = await reader.readline() |             msgback = await reader.readline() | ||||||
|             writer.close() |             writer.close() | ||||||
|  |             await writer.wait_closed() | ||||||
|             return msgback |             return msgback | ||||||
| 
 | 
 | ||||||
|         messages = [] |         messages = [] | ||||||
|  | @ -987,6 +991,25 @@ def test_async_writer_api(self): | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(messages, []) |         self.assertEqual(messages, []) | ||||||
| 
 | 
 | ||||||
|  |     def test_eof_feed_when_closing_writer(self): | ||||||
|  |         # See http://bugs.python.org/issue35065 | ||||||
|  |         messages = [] | ||||||
|  |         self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx)) | ||||||
|  | 
 | ||||||
|  |         with test_utils.run_test_server() as httpd: | ||||||
|  |             rd, wr = self.loop.run_until_complete( | ||||||
|  |                 asyncio.open_connection(*httpd.address, | ||||||
|  |                                         loop=self.loop)) | ||||||
|  | 
 | ||||||
|  |             f = wr.aclose() | ||||||
|  |             self.loop.run_until_complete(f) | ||||||
|  |             assert rd.at_eof() | ||||||
|  |             f = rd.read() | ||||||
|  |             data = self.loop.run_until_complete(f) | ||||||
|  |             assert data == b'' | ||||||
|  | 
 | ||||||
|  |         self.assertEqual(messages, []) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     unittest.main() |     unittest.main() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | Remove `StreamReaderProtocol._untrack_reader`. The call to `_untrack_reader` | ||||||
|  | is currently performed too soon, causing the protocol to forget about the | ||||||
|  | reader before `connection_lost` can run and feed the EOF to the reader. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vincent Michel
						Vincent Michel